diff --git a/packages/babel-generator/src/node/index.js b/packages/babel-generator/src/node/index.js index 394e63b5cbdd..faf700dc681b 100644 --- a/packages/babel-generator/src/node/index.js +++ b/packages/babel-generator/src/node/index.js @@ -97,5 +97,18 @@ export function needsParens(node, parent, printStack) { 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( + * "??", + * t.logicalExpression("||", t.identifier("a"), t.identifier("b")), + * t.identifier("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 parenthesis 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..826610d2b85d 100644 --- a/packages/babel-generator/test/index.js +++ b/packages/babel-generator/test/index.js @@ -298,6 +298,31 @@ 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/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 9b48c7129e2f..9aeaa5b26d9d 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -380,6 +380,39 @@ export default class ExpressionParser extends LValParser { node.right = this.parseExprOpRightExpr(op, prec, noIn); + /* 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 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 to have parenthesis + * if the parenthesis is missing we raise an error and throw it + */ + if (op === tt.nullishCoalescing) { + if ( + left.type === "LogicalExpression" && + left.operator !== "??" && + !(left.extra && left.extra.parenthesized) + ) { + throw this.raise( + left.start, + `Nullish coalescing operator(??) requires parens when mixing with logical operators`, + ); + } else if ( + node.right.type === "LogicalExpression" && + node.right.operator !== "??" && + !(node.right.extra && node.right.extra.parenthesized) + ) { + throw this.raise( + node.right.start, + `Nullish coalescing operator(??) requires parens when mixing with logical operators`, + ); + } + } + this.finishNode( node, op === tt.logicalOR || diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 34fd891c9256..47b4ced9f14e 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, }), @@ -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 }), 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/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..b79520d826a2 --- /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": "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/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..e95e6eb0b428 --- /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": "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/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..dc240a52b3ad --- /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": "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/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..b79520d826a2 --- /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": "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/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" }, 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..64a69051963b --- /dev/null +++ b/packages/babel-parser/test/unit/tokenizer/types.js @@ -0,0 +1,15 @@ +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); + }); +}); 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