From 2ea36b62d330fa13eb5e38a2399930b3e27bc00c Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Wed, 24 Jul 2019 14:23:39 +0530 Subject: [PATCH 01/13] :recycle: added condition to check for left and right of nullish coalescing operator and if any is a logical expression without a paren then throw an error --- .../babel-parser/src/parser/expression.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 9b48c7129e2f..88eda16283e1 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -380,6 +380,28 @@ export default class ExpressionParser extends LValParser { node.right = this.parseExprOpRightExpr(op, prec, noIn); + if (op === tt.nullishCoalescing) { + if ( + left.type === "LogicalExpression" && + left.operator !== "??" && + !(left.extra && left.extra.parenthesized) + ) { + throw this.raise( + this.state.start, + `Wrap left hand side of the expression in parentheses`, + ); + } else if ( + node.right.type === "LogicalExpression" && + node.right.operator !== "??" && + !(node.right.extra && node.right.extra.parenthesized) + ) { + throw this.raise( + this.state.start, + `Wrap right hand side of the expression in parentheses.`, + ); + } + } + this.finishNode( node, op === tt.logicalOR || From 2ec028cf02fe7cd40534c3f822e175e2c15cbd0a Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 02:56:38 +0530 Subject: [PATCH 02/13] :bug: bugs fixed and test cases updated for babel parser --- .../babel-parser/src/parser/expression.js | 16 +++- .../and-nullish/input.js | 2 +- .../and-nullish/output.json | 52 +++++------ .../no-paren-and-nullish/input.js | 1 + .../no-paren-and-nullish/options.json | 7 ++ .../no-paren-nullish-and/input.js | 1 + .../no-paren-nullish-and/options.json | 6 ++ .../no-paren-nullish-or/input.js | 1 + .../no-paren-nullish-or/options.json | 6 ++ .../no-paren-or-nullish/input.js | 1 + .../no-paren-or-nullish/options.json | 7 ++ .../nullish-and/input.js | 2 +- .../nullish-and/output.json | 44 +++++----- .../nullish-or/input.js | 2 +- .../nullish-or/output.json | 86 ++++++++++--------- .../or-nullish/input.js | 2 +- .../or-nullish/output.json | 52 +++++------ 17 files changed, 173 insertions(+), 115 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 88eda16283e1..bf10f1555d67 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -380,6 +380,18 @@ export default class ExpressionParser extends LValParser { node.right = this.parseExprOpRightExpr(op, prec, noIn); + if (op === tt.logicalOR) { + if ( + left.type === "LogicalExpression" && + left.operator === "??" && + !(left.extra && left.extra.parenthesized) + ) { + throw this.raise( + left.start, + `Wrap left hand side of the expression in parentheses`, + ); + } + } if (op === tt.nullishCoalescing) { if ( left.type === "LogicalExpression" && @@ -387,7 +399,7 @@ export default class ExpressionParser extends LValParser { !(left.extra && left.extra.parenthesized) ) { throw this.raise( - this.state.start, + left.start, `Wrap left hand side of the expression in parentheses`, ); } else if ( @@ -396,7 +408,7 @@ export default class ExpressionParser extends LValParser { !(node.right.extra && node.right.extra.parenthesized) ) { throw this.raise( - this.state.start, + node.right.start, `Wrap right hand side of the expression in parentheses.`, ); } diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/input.js index 2b0c8c8ff80a..4080eadc3962 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/input.js +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/input.js @@ -1 +1 @@ -a && b ?? c; +(a && b) ?? c; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/output.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/output.json index 779d2ccfbcc8..31a372d44df5 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/output.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/and-nullish/output.json @@ -1,7 +1,7 @@ { "type": "File", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -9,13 +9,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "program": { "type": "Program", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -23,7 +23,7 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "sourceType": "script", @@ -32,7 +32,7 @@ { "type": "ExpressionStatement", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -40,13 +40,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "expression": { "type": "LogicalExpression", "start": 0, - "end": 11, + "end": 13, "loc": { "start": { "line": 1, @@ -54,35 +54,35 @@ }, "end": { "line": 1, - "column": 11 + "column": 13 } }, "left": { "type": "LogicalExpression", - "start": 0, - "end": 6, + "start": 1, + "end": 7, "loc": { "start": { "line": 1, - "column": 0 + "column": 1 }, "end": { "line": 1, - "column": 6 + "column": 7 } }, "left": { "type": "Identifier", - "start": 0, - "end": 1, + "start": 1, + "end": 2, "loc": { "start": { "line": 1, - "column": 0 + "column": 1 }, "end": { "line": 1, - "column": 1 + "column": 2 }, "identifierName": "a" }, @@ -91,35 +91,39 @@ "operator": "&&", "right": { "type": "Identifier", - "start": 5, - "end": 6, + "start": 6, + "end": 7, "loc": { "start": { "line": 1, - "column": 5 + "column": 6 }, "end": { "line": 1, - "column": 6 + "column": 7 }, "identifierName": "b" }, "name": "b" + }, + "extra": { + "parenthesized": true, + "parenStart": 0 } }, "operator": "??", "right": { "type": "Identifier", - "start": 10, - "end": 11, + "start": 12, + "end": 13, "loc": { "start": { "line": 1, - "column": 10 + "column": 12 }, "end": { "line": 1, - "column": 11 + "column": 13 }, "identifierName": "c" }, diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/input.js new file mode 100644 index 000000000000..650d93b39a30 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/input.js @@ -0,0 +1 @@ +c && d ?? e; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json new file mode 100644 index 000000000000..88e9c69ae088 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + "nullishCoalescingOperator", + "estree" + ], + "throws": "Wrap left hand side of the expression in parentheses (1:0)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/input.js new file mode 100644 index 000000000000..b8805af4953d --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/input.js @@ -0,0 +1 @@ +a ?? b && c; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json new file mode 100644 index 000000000000..286f453dbe79 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "nullishCoalescingOperator" + ], + "throws": "Wrap right hand side of the expression in parentheses. (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/input.js new file mode 100644 index 000000000000..1fd223be11f9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/input.js @@ -0,0 +1 @@ +e ?? f ?? g || h; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json new file mode 100644 index 000000000000..2b97cbee3275 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "nullishCoalescingOperator" + ], + "throws": "Wrap left hand side of the expression in parentheses (1:0)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/input.js new file mode 100644 index 000000000000..5647ff20498f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/input.js @@ -0,0 +1 @@ +h || i ?? j; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json new file mode 100644 index 000000000000..88e9c69ae088 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + "nullishCoalescingOperator", + "estree" + ], + "throws": "Wrap left hand side of the expression in parentheses (1:0)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/input.js index b8805af4953d..886259bfb68d 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/input.js +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/input.js @@ -1 +1 @@ -a ?? b && c; +a ?? (b && c); diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/output.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/output.json index 2e4c3bf5553f..b01e3ccaf935 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/output.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-and/output.json @@ -1,7 +1,7 @@ { "type": "File", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -9,13 +9,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "program": { "type": "Program", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -23,7 +23,7 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "sourceType": "script", @@ -32,7 +32,7 @@ { "type": "ExpressionStatement", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -40,13 +40,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "expression": { "type": "LogicalExpression", "start": 0, - "end": 11, + "end": 13, "loc": { "start": { "line": 1, @@ -54,7 +54,7 @@ }, "end": { "line": 1, - "column": 11 + "column": 13 } }, "left": { @@ -77,30 +77,30 @@ "operator": "??", "right": { "type": "LogicalExpression", - "start": 5, - "end": 11, + "start": 6, + "end": 12, "loc": { "start": { "line": 1, - "column": 5 + "column": 6 }, "end": { "line": 1, - "column": 11 + "column": 12 } }, "left": { "type": "Identifier", - "start": 5, - "end": 6, + "start": 6, + "end": 7, "loc": { "start": { "line": 1, - "column": 5 + "column": 6 }, "end": { "line": 1, - "column": 6 + "column": 7 }, "identifierName": "b" }, @@ -109,20 +109,24 @@ "operator": "&&", "right": { "type": "Identifier", - "start": 10, - "end": 11, + "start": 11, + "end": 12, "loc": { "start": { "line": 1, - "column": 10 + "column": 11 }, "end": { "line": 1, - "column": 11 + "column": 12 }, "identifierName": "c" }, "name": "c" + }, + "extra": { + "parenthesized": true, + "parenStart": 5 } } } diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/input.js index 40ec9c39d17f..12162ba162d9 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/input.js +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/input.js @@ -1 +1 @@ -a ?? b || c; +a ?? (b || c); diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/output.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/output.json index 5ab0fcc1a530..6947e6097892 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/output.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/nullish-or/output.json @@ -1,7 +1,7 @@ { "type": "File", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -9,13 +9,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "program": { "type": "Program", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -23,7 +23,7 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "sourceType": "script", @@ -32,7 +32,7 @@ { "type": "ExpressionStatement", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -40,13 +40,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "expression": { "type": "LogicalExpression", "start": 0, - "end": 11, + "end": 13, "loc": { "start": { "line": 1, @@ -54,76 +54,80 @@ }, "end": { "line": 1, - "column": 11 + "column": 13 } }, "left": { - "type": "LogicalExpression", + "type": "Identifier", "start": 0, - "end": 6, + "end": 1, "loc": { "start": { "line": 1, "column": 0 }, "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "operator": "??", + "right": { + "type": "LogicalExpression", + "start": 6, + "end": 12, + "loc": { + "start": { "line": 1, "column": 6 + }, + "end": { + "line": 1, + "column": 12 } }, "left": { "type": "Identifier", - "start": 0, - "end": 1, + "start": 6, + "end": 7, "loc": { "start": { "line": 1, - "column": 0 + "column": 6 }, "end": { "line": 1, - "column": 1 + "column": 7 }, - "identifierName": "a" + "identifierName": "b" }, - "name": "a" + "name": "b" }, - "operator": "??", + "operator": "||", "right": { "type": "Identifier", - "start": 5, - "end": 6, + "start": 11, + "end": 12, "loc": { "start": { "line": 1, - "column": 5 + "column": 11 }, "end": { "line": 1, - "column": 6 + "column": 12 }, - "identifierName": "b" + "identifierName": "c" }, - "name": "b" - } - }, - "operator": "||", - "right": { - "type": "Identifier", - "start": 10, - "end": 11, - "loc": { - "start": { - "line": 1, - "column": 10 - }, - "end": { - "line": 1, - "column": 11 - }, - "identifierName": "c" + "name": "c" }, - "name": "c" + "extra": { + "parenthesized": true, + "parenStart": 5 + } } } } diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/input.js b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/input.js index b74eae4c99e2..a8204525df1a 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/input.js +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/input.js @@ -1 +1 @@ -a || b ?? c; +(a || b) ?? c; diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/output.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/output.json index 0db4055d3a89..f2e2798e4046 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/output.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/or-nullish/output.json @@ -1,7 +1,7 @@ { "type": "File", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -9,13 +9,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "program": { "type": "Program", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -23,7 +23,7 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "sourceType": "script", @@ -32,7 +32,7 @@ { "type": "ExpressionStatement", "start": 0, - "end": 12, + "end": 14, "loc": { "start": { "line": 1, @@ -40,13 +40,13 @@ }, "end": { "line": 1, - "column": 12 + "column": 14 } }, "expression": { "type": "LogicalExpression", "start": 0, - "end": 11, + "end": 13, "loc": { "start": { "line": 1, @@ -54,35 +54,35 @@ }, "end": { "line": 1, - "column": 11 + "column": 13 } }, "left": { "type": "LogicalExpression", - "start": 0, - "end": 6, + "start": 1, + "end": 7, "loc": { "start": { "line": 1, - "column": 0 + "column": 1 }, "end": { "line": 1, - "column": 6 + "column": 7 } }, "left": { "type": "Identifier", - "start": 0, - "end": 1, + "start": 1, + "end": 2, "loc": { "start": { "line": 1, - "column": 0 + "column": 1 }, "end": { "line": 1, - "column": 1 + "column": 2 }, "identifierName": "a" }, @@ -91,35 +91,39 @@ "operator": "||", "right": { "type": "Identifier", - "start": 5, - "end": 6, + "start": 6, + "end": 7, "loc": { "start": { "line": 1, - "column": 5 + "column": 6 }, "end": { "line": 1, - "column": 6 + "column": 7 }, "identifierName": "b" }, "name": "b" + }, + "extra": { + "parenthesized": true, + "parenStart": 0 } }, "operator": "??", "right": { "type": "Identifier", - "start": 10, - "end": 11, + "start": 12, + "end": 13, "loc": { "start": { "line": 1, - "column": 10 + "column": 12 }, "end": { "line": 1, - "column": 11 + "column": 13 }, "identifierName": "c" }, From 82a6ac2ff04b0dbca0d88bf8a1b4b436148b3ec8 Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 03:02:31 +0530 Subject: [PATCH 03/13] :recycle: code comments added --- packages/babel-parser/src/parser/expression.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index bf10f1555d67..9a6e6fca1f80 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -380,6 +380,14 @@ export default class ExpressionParser extends LValParser { node.right = this.parseExprOpRightExpr(op, prec, noIn); + /* this check is needed because for operations like + * a ?? b || c + * a ?? b => This is considered as a logical expression in the ast tree + * c => Identifier + * so we need to check, only for || cases that if left is logical expression without paren + * then raise an error + */ + if (op === tt.logicalOR) { if ( left.type === "LogicalExpression" && @@ -392,6 +400,16 @@ export default class ExpressionParser extends LValParser { ); } } + /* this check is for all && and ?? operators + * a ?? b && c for this example + * b && c => This is considered as a logical expression in the ast tree + * a => Identifier + * so for ?? operator we need to check in this case the right expression + * second case a && b ?? c + * here a && b => This is considered as a logical expression in the ast tree + * c => identifer + * so now here for ?? operator we need to check the left expression + */ if (op === tt.nullishCoalescing) { if ( left.type === "LogicalExpression" && From 823d998c5983fa7301d356d317f0aac35552bbfe Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 03:18:42 +0530 Subject: [PATCH 04/13] :bug: spell error rectified --- packages/babel-parser/src/parser/expression.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 9a6e6fca1f80..27c0992f1a28 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -396,7 +396,7 @@ export default class ExpressionParser extends LValParser { ) { throw this.raise( left.start, - `Wrap left hand side of the expression in parentheses`, + `Wrap left hand side of the expression in parenthesis`, ); } } @@ -418,7 +418,7 @@ export default class ExpressionParser extends LValParser { ) { throw this.raise( left.start, - `Wrap left hand side of the expression in parentheses`, + `Wrap left hand side of the expression in parenthesis`, ); } else if ( node.right.type === "LogicalExpression" && @@ -427,7 +427,7 @@ export default class ExpressionParser extends LValParser { ) { throw this.raise( node.right.start, - `Wrap right hand side of the expression in parentheses.`, + `Wrap right hand side of the expression in parenthesis.`, ); } } From a7037dd5902e6e58311d8d35cc70586df5437455 Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 03:31:48 +0530 Subject: [PATCH 05/13] :recycle: failing test updated --- .../no-paren-and-nullish/options.json | 9 +++------ .../no-paren-nullish-and/options.json | 8 +++----- .../no-paren-nullish-or/options.json | 8 +++----- .../no-paren-or-nullish/options.json | 9 +++------ 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json index 88e9c69ae088..68a4874b0762 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json @@ -1,7 +1,4 @@ { - "plugins": [ - "nullishCoalescingOperator", - "estree" - ], - "throws": "Wrap left hand side of the expression in parentheses (1:0)" -} \ No newline at end of file + "plugins": ["nullishCoalescingOperator", "estree"], + "throws": "Wrap left hand side of the expression in parenthesis (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json index 286f453dbe79..04dafdc66f9d 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json @@ -1,6 +1,4 @@ { - "plugins": [ - "nullishCoalescingOperator" - ], - "throws": "Wrap right hand side of the expression in parentheses. (1:5)" -} \ No newline at end of file + "plugins": ["nullishCoalescingOperator"], + "throws": "Wrap right hand side of the expression in parenthesis. (1:5)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json index 2b97cbee3275..d20df430eb8a 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json @@ -1,6 +1,4 @@ { - "plugins": [ - "nullishCoalescingOperator" - ], - "throws": "Wrap left hand side of the expression in parentheses (1:0)" -} \ No newline at end of file + "plugins": ["nullishCoalescingOperator"], + "throws": "Wrap left hand side of the expression in parenthesis (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json index 88e9c69ae088..68a4874b0762 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json @@ -1,7 +1,4 @@ { - "plugins": [ - "nullishCoalescingOperator", - "estree" - ], - "throws": "Wrap left hand side of the expression in parentheses (1:0)" -} \ No newline at end of file + "plugins": ["nullishCoalescingOperator", "estree"], + "throws": "Wrap left hand side of the expression in parenthesis (1:0)" +} From 0fb1916a0622c5612aca2e66e4a663e87c5c52ad Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 03:37:10 +0530 Subject: [PATCH 06/13] :bug: push tests after make build --- .../no-paren-and-nullish/options.json | 7 +++++-- .../no-paren-nullish-and/options.json | 6 ++++-- .../no-paren-nullish-or/options.json | 6 ++++-- .../no-paren-or-nullish/options.json | 7 +++++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json index 68a4874b0762..af16c19bb8f9 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json @@ -1,4 +1,7 @@ { - "plugins": ["nullishCoalescingOperator", "estree"], + "plugins": [ + "nullishCoalescingOperator", + "estree" + ], "throws": "Wrap left hand side of the expression in parenthesis (1:0)" -} +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json index 04dafdc66f9d..426a105218d2 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json @@ -1,4 +1,6 @@ { - "plugins": ["nullishCoalescingOperator"], + "plugins": [ + "nullishCoalescingOperator" + ], "throws": "Wrap right hand side of the expression in parenthesis. (1:5)" -} +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json index d20df430eb8a..5aa26c43ef10 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json @@ -1,4 +1,6 @@ { - "plugins": ["nullishCoalescingOperator"], + "plugins": [ + "nullishCoalescingOperator" + ], "throws": "Wrap left hand side of the expression in parenthesis (1:0)" -} +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json index 68a4874b0762..af16c19bb8f9 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json @@ -1,4 +1,7 @@ { - "plugins": ["nullishCoalescingOperator", "estree"], + "plugins": [ + "nullishCoalescingOperator", + "estree" + ], "throws": "Wrap left hand side of the expression in parenthesis (1:0)" -} +} \ No newline at end of file From 3260bef0dfaa38c0b7270b60d3b5425f30e26bc1 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 25 Jul 2019 23:16:37 -0400 Subject: [PATCH 07/13] Skip nullish-coalescing flow precedence tests They're now incorrect --- scripts/tests/flow/flow_tests_whitelist.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/tests/flow/flow_tests_whitelist.txt b/scripts/tests/flow/flow_tests_whitelist.txt index 7549e6a49ae1..43f45ad565ad 100644 --- a/scripts/tests/flow/flow_tests_whitelist.txt +++ b/scripts/tests/flow/flow_tests_whitelist.txt @@ -29,3 +29,5 @@ class_method_kinds/polymorphic_getter.js ES6/modules/migrated_0020.js export_import_reserved_words/migrated_0003.js export_statements/export_trailing_comma.js +nullish_coalescing/precedence_and.js +nullish_coalescing/precedence_or.js From 6a0de8b84068c81a73c1147ab51310b4d3ee1b2e Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Fri, 26 Jul 2019 18:56:27 +0530 Subject: [PATCH 08/13] :recycle: error message updated, binop priority of other logical operators +1 from ?? and --- .../babel-parser/src/parser/expression.js | 31 ++------ packages/babel-parser/src/tokenizer/types.js | 26 +++---- .../core/opts/tokens-true/output.json | 2 +- .../no-paren-and-nullish/options.json | 2 +- .../no-paren-nullish-and/options.json | 2 +- .../no-paren-nullish-or/options.json | 2 +- .../no-paren-or-nullish/options.json | 2 +- .../fixtures/typescript/cast/as/output.json | 74 +++++++++---------- 8 files changed, 61 insertions(+), 80 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 27c0992f1a28..9aeaa5b26d9d 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -380,35 +380,16 @@ export default class ExpressionParser extends LValParser { node.right = this.parseExprOpRightExpr(op, prec, noIn); - /* this check is needed because for operations like - * a ?? b || c - * a ?? b => This is considered as a logical expression in the ast tree - * c => Identifier - * so we need to check, only for || cases that if left is logical expression without paren - * then raise an error - */ - - if (op === tt.logicalOR) { - if ( - left.type === "LogicalExpression" && - left.operator === "??" && - !(left.extra && left.extra.parenthesized) - ) { - throw this.raise( - left.start, - `Wrap left hand side of the expression in parenthesis`, - ); - } - } - /* this check is for all && and ?? operators + /* this check is for all ?? operators * a ?? b && c for this example * b && c => This is considered as a logical expression in the ast tree * a => Identifier - * so for ?? operator we need to check in this case the right expression + * so for ?? operator we need to check in this case the right expression to have parenthesis * second case a && b ?? c * here a && b => This is considered as a logical expression in the ast tree * c => identifer - * so now here for ?? operator we need to check the left expression + * so now here for ?? operator we need to check the left expression to have parenthesis + * if the parenthesis is missing we raise an error and throw it */ if (op === tt.nullishCoalescing) { if ( @@ -418,7 +399,7 @@ export default class ExpressionParser extends LValParser { ) { throw this.raise( left.start, - `Wrap left hand side of the expression in parenthesis`, + `Nullish coalescing operator(??) requires parens when mixing with logical operators`, ); } else if ( node.right.type === "LogicalExpression" && @@ -427,7 +408,7 @@ export default class ExpressionParser extends LValParser { ) { throw this.raise( node.right.start, - `Wrap right hand side of the expression in parenthesis.`, + `Nullish coalescing operator(??) requires parens when mixing with logical operators`, ); } } diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 34fd891c9256..7a559a758ed2 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -139,21 +139,21 @@ export const types: { [name: string]: TokenType } = { tilde: new TokenType("~", { beforeExpr, prefix, startsExpr }), pipeline: createBinop("|>", 0), nullishCoalescing: createBinop("??", 1), - logicalOR: createBinop("||", 1), - logicalAND: createBinop("&&", 2), - bitwiseOR: createBinop("|", 3), - bitwiseXOR: createBinop("^", 4), - bitwiseAND: createBinop("&", 5), - equality: createBinop("==/!=/===/!==", 6), - relational: createBinop("/<=/>=", 7), - bitShift: createBinop("<>/>>>", 8), - plusMin: new TokenType("+/-", { beforeExpr, binop: 9, prefix, startsExpr }), - modulo: createBinop("%", 10), - star: createBinop("*", 10), - slash: createBinop("/", 10), + logicalOR: createBinop("||", 2), + logicalAND: createBinop("&&", 3), + bitwiseOR: createBinop("|", 4), + bitwiseXOR: createBinop("^", 5), + bitwiseAND: createBinop("&", 6), + equality: createBinop("==/!=/===/!==", 7), + relational: createBinop("/<=/>=", 8), + bitShift: createBinop("<>/>>>", 9), + plusMin: new TokenType("+/-", { beforeExpr, binop: 10, prefix, startsExpr }), + modulo: createBinop("%", 11), + star: createBinop("*", 11), + slash: createBinop("/", 11), exponent: new TokenType("**", { beforeExpr, - binop: 11, + binop: 12, rightAssociative: true, }), diff --git a/packages/babel-parser/test/fixtures/core/opts/tokens-true/output.json b/packages/babel-parser/test/fixtures/core/opts/tokens-true/output.json index 47117344de0f..a21bf5e27309 100644 --- a/packages/babel-parser/test/fixtures/core/opts/tokens-true/output.json +++ b/packages/babel-parser/test/fixtures/core/opts/tokens-true/output.json @@ -457,7 +457,7 @@ "isAssign": false, "prefix": true, "postfix": false, - "binop": 9, + "binop": 10, "updateContext": null }, "value": "+", diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json index af16c19bb8f9..b79520d826a2 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-and-nullish/options.json @@ -3,5 +3,5 @@ "nullishCoalescingOperator", "estree" ], - "throws": "Wrap left hand side of the expression in parenthesis (1:0)" + "throws": "Nullish coalescing operator(??) requires parens when mixing with logical operators (1:0)" } \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json index 426a105218d2..e95e6eb0b428 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-and/options.json @@ -2,5 +2,5 @@ "plugins": [ "nullishCoalescingOperator" ], - "throws": "Wrap right hand side of the expression in parenthesis. (1:5)" + "throws": "Nullish coalescing operator(??) requires parens when mixing with logical operators (1:5)" } \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json index 5aa26c43ef10..dc240a52b3ad 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-nullish-or/options.json @@ -2,5 +2,5 @@ "plugins": [ "nullishCoalescingOperator" ], - "throws": "Wrap left hand side of the expression in parenthesis (1:0)" + "throws": "Nullish coalescing operator(??) requires parens when mixing with logical operators (1:10)" } \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json index af16c19bb8f9..b79520d826a2 100644 --- a/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json +++ b/packages/babel-parser/test/fixtures/experimental/nullish-coalescing-operator/no-paren-or-nullish/options.json @@ -3,5 +3,5 @@ "nullishCoalescingOperator", "estree" ], - "throws": "Wrap left hand side of the expression in parenthesis (1:0)" + "throws": "Nullish coalescing operator(??) requires parens when mixing with logical operators (1:0)" } \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/cast/as/output.json b/packages/babel-parser/test/fixtures/typescript/cast/as/output.json index a83b677640f6..299dbc75a813 100644 --- a/packages/babel-parser/test/fixtures/typescript/cast/as/output.json +++ b/packages/babel-parser/test/fixtures/typescript/cast/as/output.json @@ -236,7 +236,7 @@ } }, "expression": { - "type": "BinaryExpression", + "type": "TSAsExpression", "start": 49, "end": 66, "loc": { @@ -249,10 +249,10 @@ "column": 17 } }, - "left": { - "type": "Identifier", + "expression": { + "type": "BinaryExpression", "start": 49, - "end": 50, + "end": 56, "loc": { "start": { "line": 3, @@ -260,28 +260,28 @@ }, "end": { "line": 3, - "column": 1 - }, - "identifierName": "x" + "column": 7 + } }, - "name": "x" - }, - "operator": "===", - "right": { - "type": "TSAsExpression", - "start": 55, - "end": 66, - "loc": { - "start": { - "line": 3, - "column": 6 + "left": { + "type": "Identifier", + "start": 49, + "end": 50, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + }, + "identifierName": "x" }, - "end": { - "line": 3, - "column": 17 - } + "name": "x" }, - "expression": { + "operator": "===", + "right": { "type": "NumericLiteral", "start": 55, "end": 56, @@ -300,20 +300,20 @@ "raw": "1" }, "value": 1 - }, - "typeAnnotation": { - "type": "TSNumberKeyword", - "start": 60, - "end": 66, - "loc": { - "start": { - "line": 3, - "column": 11 - }, - "end": { - "line": 3, - "column": 17 - } + } + }, + "typeAnnotation": { + "type": "TSNumberKeyword", + "start": 60, + "end": 66, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 17 } } } From d9ea03c8106c2cef7726255a99e587dfab904174 Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Sat, 27 Jul 2019 01:27:43 +0530 Subject: [PATCH 09/13] :recycle: increaed the binOp for in and instanceOf, added logic to print the brackets in an ?? && || expression, test cases added --- .../src/generators/expressions.js | 6 ++--- packages/babel-generator/src/node/index.js | 12 ++++++++++ .../fixtures/types/LogicalExpression/input.js | 3 ++- .../types/LogicalExpression/options.json | 3 +++ .../types/LogicalExpression/output.js | 4 +++- packages/babel-generator/test/index.js | 23 +++++++++++++++++++ packages/babel-parser/src/tokenizer/types.js | 4 ++-- 7 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 packages/babel-generator/test/fixtures/types/LogicalExpression/options.json diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.js index 4f9a525bd05e..4ba6dd7002fd 100644 --- a/packages/babel-generator/src/generators/expressions.js +++ b/packages/babel-generator/src/generators/expressions.js @@ -227,10 +227,8 @@ export function BindExpression(node: Object) { this.print(node.callee, node); } -export { - AssignmentExpression as BinaryExpression, - AssignmentExpression as LogicalExpression, -}; +export { AssignmentExpression as BinaryExpression }; +export { AssignmentExpression as LogicalExpression }; export function MemberExpression(node: Object) { this.print(node.object, node); diff --git a/packages/babel-generator/src/node/index.js b/packages/babel-generator/src/node/index.js index 394e63b5cbdd..f9d337351ce8 100644 --- a/packages/babel-generator/src/node/index.js +++ b/packages/babel-generator/src/node/index.js @@ -96,6 +96,18 @@ export function needsParens(node, parent, printStack) { if (t.isNewExpression(parent) && parent.callee === node) { if (isOrHasCallExpression(node)) return true; } + /* this check if for NullishCoalescing with LogicalOperators liks && and || + * For example when someone creates an ast programmaticaly like this + * t.logicalExpression( + * "??", + * t.logicalExpression("||", t.identifier("a"), t.identifier("b")), + * t.identifier("c"), + * ); + * In the above case we should that AST is equivalent to writing a || b ?? c + * This is incorrect because NullishCoalescing when used with LogicalExpressions should have parenthesis + * The correct syntax is (a || b) ?? c, that is why we need parens in this case + */ + if (t.isLogicalExpression(node) && parent.operator === "??") return true; return find(expandedParens, node, parent, printStack); } diff --git a/packages/babel-generator/test/fixtures/types/LogicalExpression/input.js b/packages/babel-generator/test/fixtures/types/LogicalExpression/input.js index 08cae4f71732..3ff8c4d4040e 100644 --- a/packages/babel-generator/test/fixtures/types/LogicalExpression/input.js +++ b/packages/babel-generator/test/fixtures/types/LogicalExpression/input.js @@ -1,4 +1,5 @@ foo ||bar; (x => x)|| bar; (function a(x){return x;})|| 2; -0||(function(){return alpha;}); \ No newline at end of file +0||(function(){return alpha;}); +a ?? (b || c); diff --git a/packages/babel-generator/test/fixtures/types/LogicalExpression/options.json b/packages/babel-generator/test/fixtures/types/LogicalExpression/options.json new file mode 100644 index 000000000000..1bb4736991a4 --- /dev/null +++ b/packages/babel-generator/test/fixtures/types/LogicalExpression/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["nullishCoalescingOperator"] +} diff --git a/packages/babel-generator/test/fixtures/types/LogicalExpression/output.js b/packages/babel-generator/test/fixtures/types/LogicalExpression/output.js index a27aa9ac1833..994dc9ec1b59 100644 --- a/packages/babel-generator/test/fixtures/types/LogicalExpression/output.js +++ b/packages/babel-generator/test/fixtures/types/LogicalExpression/output.js @@ -7,4 +7,6 @@ foo || bar; 0 || function () { return alpha; -}; \ No newline at end of file +}; + +a ?? (b || c); diff --git a/packages/babel-generator/test/index.js b/packages/babel-generator/test/index.js index 80bee85f9eaf..e90754cc4d4a 100644 --- a/packages/babel-generator/test/index.js +++ b/packages/babel-generator/test/index.js @@ -298,6 +298,29 @@ describe("generation", function() { }); describe("programmatic generation", function() { + it("should add parenthesis when NullishCoalescing is used along with ||", function() { + // https://github.com/babel/babel/issues/10260 + const nullishCoalesc = t.logicalExpression( + "??", + t.logicalExpression("||", t.identifier("a"), t.identifier("b")), + t.identifier("c"), + ); + const output = generate(nullishCoalesc).code; + expect(output).toBe(`(a || b) ?? c`); + }); + it("should add parenthesis when NullishCoalesing is used with &&", function() { + const nullishCoalesc = t.logicalExpression( + "??", + t.identifier("a"), + t.logicalExpression( + "&&", + t.identifier("b"), + t.logicalExpression("&&", t.identifier("c"), t.identifier("d")), + ), + ); + const output = generate(nullishCoalesc).code; + expect(output).toBe(`a ?? (b && c && d)`); + }); it("numeric member expression", function() { // Should not generate `0.foo` const mem = t.memberExpression( diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 7a559a758ed2..47b4ced9f14e 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -188,8 +188,8 @@ export const types: { [name: string]: TokenType } = { _null: createKeyword("null", { startsExpr }), _true: createKeyword("true", { startsExpr }), _false: createKeyword("false", { startsExpr }), - _in: createKeyword("in", { beforeExpr, binop: 7 }), - _instanceof: createKeyword("instanceof", { beforeExpr, binop: 7 }), + _in: createKeyword("in", { beforeExpr, binop: 8 }), + _instanceof: createKeyword("instanceof", { beforeExpr, binop: 8 }), _typeof: createKeyword("typeof", { beforeExpr, prefix, startsExpr }), _void: createKeyword("void", { beforeExpr, prefix, startsExpr }), _delete: createKeyword("delete", { beforeExpr, prefix, startsExpr }), From 6918e86d4136dac063017b293415b73094b94cce Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Sat, 27 Jul 2019 01:37:47 +0530 Subject: [PATCH 10/13] :bug: failing test fixed and comments updated --- .../src/generators/expressions.js | 6 +- packages/babel-generator/src/node/index.js | 6 +- .../fixtures/typescript/cast/as/output.json | 74 +++++++++---------- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.js index 4ba6dd7002fd..4f9a525bd05e 100644 --- a/packages/babel-generator/src/generators/expressions.js +++ b/packages/babel-generator/src/generators/expressions.js @@ -227,8 +227,10 @@ export function BindExpression(node: Object) { this.print(node.callee, node); } -export { AssignmentExpression as BinaryExpression }; -export { AssignmentExpression as LogicalExpression }; +export { + AssignmentExpression as BinaryExpression, + AssignmentExpression as LogicalExpression, +}; export function MemberExpression(node: Object) { this.print(node.object, node); diff --git a/packages/babel-generator/src/node/index.js b/packages/babel-generator/src/node/index.js index f9d337351ce8..010bca8e5ade 100644 --- a/packages/babel-generator/src/node/index.js +++ b/packages/babel-generator/src/node/index.js @@ -96,16 +96,16 @@ export function needsParens(node, parent, printStack) { if (t.isNewExpression(parent) && parent.callee === node) { if (isOrHasCallExpression(node)) return true; } - /* this check if for NullishCoalescing with LogicalOperators liks && and || + /* this check is for NullishCoalescing being used with LogicalOperators like && and || * For example when someone creates an ast programmaticaly like this * t.logicalExpression( * "??", * t.logicalExpression("||", t.identifier("a"), t.identifier("b")), * t.identifier("c"), * ); - * In the above case we should that AST is equivalent to writing a || b ?? c + * In the example above the AST is equivalent to writing a || b ?? c * This is incorrect because NullishCoalescing when used with LogicalExpressions should have parenthesis - * The correct syntax is (a || b) ?? c, that is why we need parens in this case + * The correct syntax is (a || b) ?? c, that is why we need parenthesis in this case */ if (t.isLogicalExpression(node) && parent.operator === "??") return true; diff --git a/packages/babel-parser/test/fixtures/typescript/cast/as/output.json b/packages/babel-parser/test/fixtures/typescript/cast/as/output.json index 299dbc75a813..a83b677640f6 100644 --- a/packages/babel-parser/test/fixtures/typescript/cast/as/output.json +++ b/packages/babel-parser/test/fixtures/typescript/cast/as/output.json @@ -236,7 +236,7 @@ } }, "expression": { - "type": "TSAsExpression", + "type": "BinaryExpression", "start": 49, "end": 66, "loc": { @@ -249,10 +249,10 @@ "column": 17 } }, - "expression": { - "type": "BinaryExpression", + "left": { + "type": "Identifier", "start": 49, - "end": 56, + "end": 50, "loc": { "start": { "line": 3, @@ -260,28 +260,28 @@ }, "end": { "line": 3, - "column": 7 - } + "column": 1 + }, + "identifierName": "x" }, - "left": { - "type": "Identifier", - "start": 49, - "end": 50, - "loc": { - "start": { - "line": 3, - "column": 0 - }, - "end": { - "line": 3, - "column": 1 - }, - "identifierName": "x" + "name": "x" + }, + "operator": "===", + "right": { + "type": "TSAsExpression", + "start": 55, + "end": 66, + "loc": { + "start": { + "line": 3, + "column": 6 }, - "name": "x" + "end": { + "line": 3, + "column": 17 + } }, - "operator": "===", - "right": { + "expression": { "type": "NumericLiteral", "start": 55, "end": 56, @@ -300,20 +300,20 @@ "raw": "1" }, "value": 1 - } - }, - "typeAnnotation": { - "type": "TSNumberKeyword", - "start": 60, - "end": 66, - "loc": { - "start": { - "line": 3, - "column": 11 - }, - "end": { - "line": 3, - "column": 17 + }, + "typeAnnotation": { + "type": "TSNumberKeyword", + "start": 60, + "end": 66, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 17 + } } } } From 417cd403312f86287401824e83cb096441650d54 Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Sat, 27 Jul 2019 02:25:40 +0530 Subject: [PATCH 11/13] :recycle: new lines added between tests --- packages/babel-generator/src/node/index.js | 1 + packages/babel-generator/test/index.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/babel-generator/src/node/index.js b/packages/babel-generator/src/node/index.js index 010bca8e5ade..faf700dc681b 100644 --- a/packages/babel-generator/src/node/index.js +++ b/packages/babel-generator/src/node/index.js @@ -96,6 +96,7 @@ export function needsParens(node, parent, printStack) { if (t.isNewExpression(parent) && parent.callee === node) { if (isOrHasCallExpression(node)) return true; } + /* this check is for NullishCoalescing being used with LogicalOperators like && and || * For example when someone creates an ast programmaticaly like this * t.logicalExpression( diff --git a/packages/babel-generator/test/index.js b/packages/babel-generator/test/index.js index e90754cc4d4a..826610d2b85d 100644 --- a/packages/babel-generator/test/index.js +++ b/packages/babel-generator/test/index.js @@ -308,6 +308,7 @@ describe("programmatic generation", function() { const output = generate(nullishCoalesc).code; expect(output).toBe(`(a || b) ?? c`); }); + it("should add parenthesis when NullishCoalesing is used with &&", function() { const nullishCoalesc = t.logicalExpression( "??", @@ -321,6 +322,7 @@ describe("programmatic generation", function() { const output = generate(nullishCoalesc).code; expect(output).toBe(`a ?? (b && c && d)`); }); + it("numeric member expression", function() { // Should not generate `0.foo` const mem = t.memberExpression( From 4a2d372e4ca1a6ca08cd4ec7f81fb0235ae5e02c Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Sat, 27 Jul 2019 02:26:18 +0530 Subject: [PATCH 12/13] :recycle: basic tests for checking the binOp of instanceOf, in and relational operators to be equal added --- packages/babel-parser/test/unit/tokenizer/types.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/babel-parser/test/unit/tokenizer/types.js diff --git a/packages/babel-parser/test/unit/tokenizer/types.js b/packages/babel-parser/test/unit/tokenizer/types.js new file mode 100644 index 000000000000..e9f67c6f81ff --- /dev/null +++ b/packages/babel-parser/test/unit/tokenizer/types.js @@ -0,0 +1,13 @@ +import { types } from "../../../src/tokenizer/types"; + +describe("token types", () => { + it("should check if the binOp for relational === in", () => { + expect(types.relational.binop).toEqual(types._in.binop); + }); + it("should check if the binOp for relational === instanceOf", () => { + expect(types.relational.binop).toEqual(types._instanceof.binop); + }); + it("should check if the binOp for in === instanceOf", () => { + expect(types._in.binop).toEqual(types._instanceof.binop); + }); +}); From 40eb40e34b689096d6a5921c63577904a187d4be Mon Sep 17 00:00:00 2001 From: Vivek Nayyar Date: Sat, 27 Jul 2019 02:51:31 +0530 Subject: [PATCH 13/13] :recycle: new lines added in between tests --- packages/babel-parser/test/unit/tokenizer/types.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/babel-parser/test/unit/tokenizer/types.js b/packages/babel-parser/test/unit/tokenizer/types.js index e9f67c6f81ff..64a69051963b 100644 --- a/packages/babel-parser/test/unit/tokenizer/types.js +++ b/packages/babel-parser/test/unit/tokenizer/types.js @@ -4,9 +4,11 @@ describe("token types", () => { it("should check if the binOp for relational === in", () => { expect(types.relational.binop).toEqual(types._in.binop); }); + it("should check if the binOp for relational === instanceOf", () => { expect(types.relational.binop).toEqual(types._instanceof.binop); }); + it("should check if the binOp for in === instanceOf", () => { expect(types._in.binop).toEqual(types._instanceof.binop); });