/**
* @fileoverview Disallow parenthesising higher precedence subexpressions.
* @author Michael Ficarra
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const rule = require("../../../lib/rules/no-extra-parens"),
{ RuleTester } = require("../../../lib/rule-tester");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Create error message object for failure cases
* @param {string} code source code
* @param {string} output fixed source code
* @param {string} type node type
* @param {int} line line number
* @param {Object} config rule configuration
* @returns {Object} result object
* @private
*/
function invalid(code, output, type, line, config) {
const result = {
code,
output,
parserOptions: config && config.parserOptions || {},
errors: [
{
messageId: "unexpected",
type
}
],
options: config && config.options || []
};
if (line) {
result.errors[0].line = line;
}
return result;
}
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 2022,
ecmaFeatures: {
jsx: true
}
}
});
ruleTester.run("no-extra-parens", rule, {
valid: [
// all precedence boundaries
"foo",
"a = b, c = d",
"a = b ? c : d",
"a = (b, c)",
"a || b ? c = d : e = f",
"(a = b) ? (c, d) : (e, f)",
"a && b || c && d",
"(a ? b : c) || (d ? e : f)",
"a | b && c | d",
"(a || b) && (c || d)",
"a ^ b | c ^ d",
"(a && b) | (c && d)",
"a & b ^ c & d",
"(a | b) ^ (c | d)",
"a == b & c != d",
"(a ^ b) & (c ^ d)",
"a < b === c in d",
"(a & b) !== (c & d)",
"a << b >= c >>> d",
"(a == b) instanceof (c != d)",
"a + b << c - d",
"(a <= b) >> (c > d)",
"a * b + c / d",
"(a << b) - (c >> d)",
"+a % !b",
"(a + b) * (c - d)",
"-void+delete~typeof!a",
"!(a * b); typeof (a / b); +(a % b); delete (a * b); ~(a / b); void (a % b); -(a * b)",
"a(b = c, (d, e))",
"(++a)(b); (c++)(d);",
"new (A())",
"new (foo.Baz().foo)",
"new (foo.baz.bar().foo.baz)",
"new ({}.baz.bar.foo().baz)",
"new (doSomething().baz.bar().foo)",
"new ([][0].baz.foo().bar.foo)",
"new (foo\n.baz\n.bar()\n.foo.baz)",
"new A()()",
"(new A)()",
"(new (Foo || Bar))()",
"(new new foo())()",
"new (new A)()",
"new (new a.b)()",
"new (new new foo())(bar)",
"(new foo).bar",
"(new foo)[bar]",
"(new foo).bar.baz",
"(new foo.bar).baz",
"(new foo).bar()",
"(new foo.bar).baz()",
"new (new foo).bar",
"new (new foo.bar).baz",
"(new new foo()).baz",
"(2 + 3) ** 4",
"2 ** (2 + 3)",
"new (import(source))",
"import((s,t))",
// same precedence
"a, b, c",
"a = b = c",
"a ? b ? c : d : e",
"a ? b : c ? d : e",
"a || b || c",
"a || (b || c)",
"a && b && c",
"a && (b && c)",
"a | b | c",
"a | (b | c)",
"a ^ b ^ c",
"a ^ (b ^ c)",
"a & b & c",
"a & (b & c)",
"a == b == c",
"a == (b == c)",
"a < b < c",
"a < (b < c)",
"a << b << c",
"a << (b << c)",
"a + b + c",
"a + (b + c)",
"a * b * c",
"a * (b * c)",
"!!a; typeof +b; void -c; ~delete d;",
"a(b)",
"a(b)(c)",
"a((b, c))",
"new new A",
"2 ** 3 ** 4",
"(2 ** 3) ** 4",
// constructs that contain expressions
"if(a);",
"with(a){}",
"switch(a){ case 0: break; }",
"function a(){ return b; }",
"var a = () => { return b; }",
"throw a;",
"while(a);",
"do; while(a);",
"for(;;);",
"for(a in b);",
"for(a in b, c);",
"for(a of b);",
"for (a of (b, c));",
"var a = (b, c);",
"[]",
"[a, b]",
"!{a}",
"!{a: 0, b: 1}",
"!{[a]:0}",
"!{[(a, b)]:0}",
"!{a, ...b}",
"const {a} = {}",
"const {a:b} = {}",
"const {a:b=1} = {}",
"const {[a]:b} = {}",
"const {[a]:b=1} = {}",
"const {[(a, b)]:c} = {}",
"const {a, ...b} = {}",
"class foo {}",
"class foo { constructor(){} a(){} get b(){} set b(bar){} get c(){} set d(baz){} static e(){} }",
"class foo { [a](){} get [b](){} set [b](bar){} get [c](){} set [d](baz){} static [e](){} }",
"class foo { [(a,b)](){} }",
"class foo { a(){} [b](){} c(){} [(d,e)](){} }",
"class foo { [(a,b)](){} c(){} [d](){} e(){} }",
"const foo = class { constructor(){} a(){} get b(){} set b(bar){} get c(){} set d(baz){} static e(){} }",
"class foo { x; }",
"class foo { static x; }",
"class foo { x = 1; }",
"class foo { static x = 1; }",
"class foo { #x; }",
"class foo { static #x; }",
"class foo { static #x = 1; }",
"class foo { #x(){} get #y() {} set #y(value) {} static #z(){} static get #q() {} static set #q(value) {} }",
"const foo = class { #x(){} get #y() {} set #y(value) {} static #z(){} static get #q() {} static set #q(value) {} }",
"class foo { [(x, y)]; }",
"class foo { static [(x, y)]; }",
"class foo { [(x, y)] = 1; }",
"class foo { static [(x, y)] = 1; }",
"class foo { x = (y, z); }",
"class foo { static x = (y, z); }",
"class foo { #x = (y, z); }",
"class foo { static #x = (y, z); }",
"class foo { [(1, 2)] = (3, 4) }",
"const foo = class { [(1, 2)] = (3, 4) }",
// ExpressionStatement restricted productions
"({});",
"(function(){});",
"(let[a] = b);",
"(function*(){});",
"(class{});",
// special cases
"(0).a",
"(123).a",
"(08).a",
"(09).a",
"(018).a",
"(012934).a",
"(5_000).a",
"(5_000_00).a",
"(function(){ }())",
"({a: function(){}}.a());",
"({a:0}.a ? b : c)",
// RegExp literal is allowed to have parens (#1589)
"var isA = (/^a$/).test('a');",
"var regex = (/^a$/);",
"function a(){ return (/^a$/); }",
"function a(){ return (/^a$/).test('a'); }",
"var isA = ((/^a$/)).test('a');",
// IIFE is allowed to have parens in any position (#655)
"var foo = (function() { return bar(); }())",
"var o = { foo: (function() { return bar(); }()) };",
"o.foo = (function(){ return bar(); }());",
"(function(){ return bar(); }()), (function(){ return bar(); }())",
// IIFE is allowed to have outer parens (#1004)
"var foo = (function() { return bar(); })()",
"var o = { foo: (function() { return bar(); })() };",
"o.foo = (function(){ return bar(); })();",
"(function(){ return bar(); })(), (function(){ return bar(); })()",
"function foo() { return (function(){}()); }",
// parens are required around yield
"var foo = (function*() { if ((yield foo()) + 1) { return; } }())",
// arrow functions have the precedence of an assignment expression
"(() => 0)()",
"(_ => 0)()",
"_ => 0, _ => 1",
"a = () => b = 0",
"0 ? _ => 0 : _ => 0",
"(_ => 0) || (_ => 0)",
// Object literals as arrow function bodies need parentheses
"x => ({foo: 1})",
// Exponentiation operator `**`
"1 + 2 ** 3",
"1 - 2 ** 3",
"2 ** -3",
"(-2) ** 3",
"(+2) ** 3",
"+ (2 ** 3)",
// https://github.com/eslint/eslint/issues/5789
"a => ({b: c}[d])",
"a => ({b: c}.d())",
"a => ({b: c}.d.e)",
// "functions" enables reports for function nodes only
{ code: "(0)", options: ["functions"] },
{ code: "((0))", options: ["functions"] },
{ code: "a + (b * c)", options: ["functions"] },
{ code: "a + ((b * c))", options: ["functions"] },
{ code: "(a)(b)", options: ["functions"] },
{ code: "((a))(b)", options: ["functions"] },
{ code: "a, (b = c)", options: ["functions"] },
{ code: "a, ((b = c))", options: ["functions"] },
{ code: "for(a in (0));", options: ["functions"] },
{ code: "for(a in ((0)));", options: ["functions"] },
{ code: "var a = (b = c)", options: ["functions"] },
{ code: "var a = ((b = c))", options: ["functions"] },
{ code: "_ => (a = 0)", options: ["functions"] },
{ code: "_ => ((a = 0))", options: ["functions"] },
// ["all", { conditionalAssign: false }] enables extra parens around conditional assignments
{ code: "while ((foo = bar())) {}", options: ["all", { conditionalAssign: false }] },
{ code: "if ((foo = bar())) {}", options: ["all", { conditionalAssign: false }] },
{ code: "do; while ((foo = bar()))", options: ["all", { conditionalAssign: false }] },
{ code: "for (;(a = b););", options: ["all", { conditionalAssign: false }] },
{ code: "var a = ((b = c)) ? foo : bar;", options: ["all", { conditionalAssign: false }] },
{ code: "while (((foo = bar()))) {}", options: ["all", { conditionalAssign: false }] },
{ code: "var a = (((b = c))) ? foo : bar;", options: ["all", { conditionalAssign: false }] },
// ["all", { nestedBinaryExpressions: false }] enables extra parens around conditional assignments
{ code: "a + (b * c)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "(a * b) + c", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "(a * b) / c", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "a || (b && c)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "a + ((b * c))", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "((a * b)) + c", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "((a * b)) / c", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "a || ((b && c))", options: ["all", { nestedBinaryExpressions: false }] },
// ["all", { returnAssign: false }] enables extra parens around expressions returned by return statements
{ code: "function a(b) { return b || c; }", options: ["all", { returnAssign: false }] },
{ code: "function a(b) { return; }", options: ["all", { returnAssign: false }] },
{ code: "function a(b) { return (b = 1); }", options: ["all", { returnAssign: false }] },
{ code: "function a(b) { return (b = c) || (b = d); }", options: ["all", { returnAssign: false }] },
{ code: "function a(b) { return c ? (d = b) : (e = b); }", options: ["all", { returnAssign: false }] },
{ code: "b => b || c;", options: ["all", { returnAssign: false }] },
{ code: "b => (b = 1);", options: ["all", { returnAssign: false }] },
{ code: "b => (b = c) || (b = d);", options: ["all", { returnAssign: false }] },
{ code: "b => c ? (d = b) : (e = b);", options: ["all", { returnAssign: false }] },
{ code: "b => { return b || c };", options: ["all", { returnAssign: false }] },
{ code: "b => { return (b = 1) };", options: ["all", { returnAssign: false }] },
{ code: "b => { return (b = c) || (b = d) };", options: ["all", { returnAssign: false }] },
{ code: "b => { return c ? (d = b) : (e = b) };", options: ["all", { returnAssign: false }] },
{ code: "function a(b) { return ((b = 1)); }", options: ["all", { returnAssign: false }] },
{ code: "b => ((b = 1));", options: ["all", { returnAssign: false }] },
// https://github.com/eslint/eslint/issues/3653
"(function(){}).foo(), 1, 2;",
"(function(){}).foo++;",
"(function(){}).foo() || bar;",
"(function(){}).foo() + 1;",
"(function(){}).foo() ? bar : baz;",
"(function(){}).foo.bar();",
"(function(){}.foo());",
"(function(){}.foo.bar);",
"(class{}).foo(), 1, 2;",
"(class{}).foo++;",
"(class{}).foo() || bar;",
"(class{}).foo() + 1;",
"(class{}).foo() ? bar : baz;",
"(class{}).foo.bar();",
"(class{}.foo());",
"(class{}.foo.bar);",
// https://github.com/eslint/eslint/issues/4608
"function *a() { yield b; }",
"function *a() { yield yield; }",
"function *a() { yield b, c; }",
"function *a() { yield (b, c); }",
"function *a() { yield b + c; }",
"function *a() { (yield b) + c; }",
// https://github.com/eslint/eslint/issues/4229
[
"function a() {",
" return (",
" b",
" );",
"}"
].join("\n"),
[
"function a() {",
" return (",
" ",
" );",
"}"
].join("\n"),
[
"function a() {",
" return (",
" <>>",
" );",
"}"
].join("\n"),
[
"throw (",
" a",
");"
].join("\n"),
[
"function *a() {",
" yield (",
" b",
" );",
"}"
].join("\n"),
// linebreaks before postfix update operators are not allowed
"(a\n)++",
"(a\n)--",
"(a\n\n)++",
"(a.b\n)--",
"(a\n.b\n)++",
"(a[\nb\n]\n)--",
"(a[b]\n\n)++",
// async/await
"async function a() { await (a + b) }",
"async function a() { await (a + await b) }",
"async function a() { (await a)() }",
"async function a() { new (await a) }",
"async function a() { await (a ** b) }",
"async function a() { (await a) ** b }",
{ code: "(foo instanceof bar) instanceof baz", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "(foo in bar) in baz", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "(foo + bar) + baz", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "(foo && bar) && baz", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "foo instanceof (bar instanceof baz)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "foo in (bar in baz)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "foo + (bar + baz)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "foo && (bar && baz)", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "((foo instanceof bar)) instanceof baz", options: ["all", { nestedBinaryExpressions: false }] },
{ code: "((foo in bar)) in baz", options: ["all", { nestedBinaryExpressions: false }] },
// https://github.com/eslint/eslint/issues/9019
"(async function() {});",
"(async function () { }());",
// ["all", { ignoreJSX: "all" }]
{ code: "const Component = (
", "JSXElement", 1, {
options: ["all", { ignoreJSX: "single-line" }]
}),
// ["all", { ignoreJSX: "none" }] default, same as unspecified
invalid("const Component = (
);", "const Component =
;", "JSXElement", 1, {
options: ["all", { ignoreJSX: "none" }]
}),
invalid([
"const Component = (
)"
].join("\n"), "const Component =
", "JSXElement", 1, {
options: ["all", { ignoreJSX: "none" }]
}),
// ["all", { enforceForArrowConditionals: true }]
{
code: "var a = (b) => (1 ? 2 : 3)",
output: "var a = (b) => 1 ? 2 : 3",
options: ["all", { enforceForArrowConditionals: true }],
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "var a = (b) => ((1 ? 2 : 3))",
output: "var a = (b) => (1 ? 2 : 3)",
options: ["all", { enforceForArrowConditionals: true }],
errors: [
{
messageId: "unexpected"
}
]
},
// ["all", { enforceForSequenceExpressions: true }]
{
code: "(a, b)",
output: "a, b",
options: ["all"],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
{
code: "(a, b)",
output: "a, b",
options: ["all", {}],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
{
code: "(a, b)",
output: "a, b",
options: ["all", { enforceForSequenceExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
{
code: "(foo(), bar());",
output: "foo(), bar();",
options: ["all", { enforceForSequenceExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
{
code: "if((a, b)){}",
output: "if(a, b){}",
options: ["all", { enforceForSequenceExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
{
code: "while ((val = foo(), val < 10));",
output: "while (val = foo(), val < 10);",
options: ["all", { enforceForSequenceExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "SequenceExpression"
}
]
},
// ["all", { enforceForNewInMemberExpressions: true }]
{
code: "(new foo()).bar",
output: "new foo().bar",
options: ["all"],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
{
code: "(new foo()).bar",
output: "new foo().bar",
options: ["all", {}],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
{
code: "(new foo()).bar",
output: "new foo().bar",
options: ["all", { enforceForNewInMemberExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
{
code: "(new foo())[bar]",
output: "new foo()[bar]",
options: ["all", { enforceForNewInMemberExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
{
code: "(new foo.bar()).baz",
output: "new foo.bar().baz",
options: ["all", { enforceForNewInMemberExpressions: true }],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
// enforceForFunctionPrototypeMethods
{
code: "var foo = (function(){}).call()",
output: "var foo = function(){}.call()",
options: ["all"],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.apply())",
output: "var foo = function(){}.apply()",
options: ["all"],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}).apply()",
output: "var foo = function(){}.apply()",
options: ["all", {}],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.call())",
output: "var foo = function(){}.call()",
options: ["all", {}],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}).call()",
output: "var foo = function(){}.call()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}).apply()",
output: "var foo = function(){}.apply()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.call())",
output: "var foo = function(){}.call()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}.apply())",
output: "var foo = function(){}.apply()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}.call)()", // removing these parens does not cause any conflicts with wrap-iife
output: "var foo = function(){}.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "MemberExpression"
}
]
},
{
code: "var foo = (function(){}.apply)()", // removing these parens does not cause any conflicts with wrap-iife
output: "var foo = function(){}.apply()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "MemberExpression"
}
]
},
{
code: "var foo = (function(){}).call",
output: "var foo = function(){}.call",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.call)",
output: "var foo = function(){}.call",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "MemberExpression"
}
]
},
{
code: "var foo = new (function(){}).call()",
output: "var foo = new function(){}.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (new function(){}.call())",
output: "var foo = new function(){}.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "NewExpression"
}
]
},
{
code: "var foo = (function(){})[call]()",
output: "var foo = function(){}[call]()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}[apply]())",
output: "var foo = function(){}[apply]()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}).bar()",
output: "var foo = function(){}.bar()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.bar())",
output: "var foo = function(){}.bar()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (function(){}).call.call()",
output: "var foo = function(){}.call.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "FunctionExpression"
}
]
},
{
code: "var foo = (function(){}.call.call())",
output: "var foo = function(){}.call.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (call())",
output: "var foo = call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (apply())",
output: "var foo = apply()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = (bar).call()",
output: "var foo = bar.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "Identifier"
}
]
},
{
code: "var foo = (bar.call())",
output: "var foo = bar.call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "((() => {}).call())",
output: "(() => {}).call()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "CallExpression"
}
]
},
{
code: "var foo = function(){}.call((a.b))",
output: "var foo = function(){}.call(a.b)",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "MemberExpression"
}
]
},
{
code: "var foo = function(){}.call((a).b)",
output: "var foo = function(){}.call(a.b)",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "Identifier"
}
]
},
{
code: "var foo = function(){}[('call')]()",
output: "var foo = function(){}['call']()",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
errors: [
{
messageId: "unexpected",
type: "Literal"
}
]
},
// https://github.com/eslint/eslint/issues/8175
invalid(
"let a = [...(b)]",
"let a = [...b]",
"Identifier",
1
),
invalid(
"let a = {...(b)}",
"let a = {...b}",
"Identifier",
1
),
invalid(
"let a = {...(b)}",
"let a = {...b}",
"Identifier",
1,
{ parserOptions: { ecmaVersion: 2018 } }
),
invalid(
"let a = [...((b, c))]",
"let a = [...(b, c)]",
"SequenceExpression",
1
),
invalid(
"let a = {...((b, c))}",
"let a = {...(b, c)}",
"SequenceExpression",
1
),
invalid(
"let a = {...((b, c))}",
"let a = {...(b, c)}",
"SequenceExpression",
1,
{ parserOptions: { ecmaVersion: 2018 } }
),
invalid(
"class A extends (B) {}",
"class A extends B {}",
"Identifier",
1
),
invalid(
"const A = class extends (B) {}",
"const A = class extends B {}",
"Identifier",
1
),
invalid(
"class A extends ((B=C)) {}",
"class A extends (B=C) {}",
"AssignmentExpression",
1
),
invalid(
"const A = class extends ((B=C)) {}",
"const A = class extends (B=C) {}",
"AssignmentExpression",
1
),
invalid(
"class A extends ((++foo)) {}",
"class A extends (++foo) {}",
"UpdateExpression",
1
),
invalid(
"export default ((a, b))",
"export default (a, b)",
"SequenceExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default (() => {})",
"export default () => {}",
"ArrowFunctionExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default ((a, b) => a + b)",
"export default (a, b) => a + b",
"ArrowFunctionExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default (a => a)",
"export default a => a",
"ArrowFunctionExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default (a = b)",
"export default a = b",
"AssignmentExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default (a ? b : c)",
"export default a ? b : c",
"ConditionalExpression",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"export default (a)",
"export default a",
"Identifier",
1,
{ parserOptions: { sourceType: "module" } }
),
invalid(
"for (foo of(bar));",
"for (foo of bar);",
"Identifier",
1
),
invalid(
"for ((foo) of bar);",
"for (foo of bar);",
"Identifier",
1
),
invalid(
"for (foo of (baz = bar));",
"for (foo of baz = bar);",
"AssignmentExpression",
1
),
invalid(
"function* f() { for (foo of (yield bar)); }",
"function* f() { for (foo of yield bar); }",
"YieldExpression",
1
),
invalid(
"for (foo of ((bar, baz)));",
"for (foo of (bar, baz));",
"SequenceExpression",
1
),
invalid(
"for ((foo)in bar);",
"for (foo in bar);",
"Identifier",
1
),
invalid(
"for ((foo['bar'])of baz);",
"for (foo['bar']of baz);",
"MemberExpression",
1
),
invalid(
"() => (({ foo: 1 }).foo)",
"() => ({ foo: 1 }).foo",
"MemberExpression",
1
),
invalid(
"(let).foo",
"let.foo",
"Identifier",
1
),
// ForStatement#init expression cannot start with `let[`, but it can start with `let` if it isn't followed by `[`
invalid(
"for ((let);;);",
"for (let;;);",
"Identifier",
1
),
invalid(
"for ((let = 1);;);",
"for (let = 1;;);",
"AssignmentExpression",
1
),
invalid(
"for ((let) = 1;;);",
"for (let = 1;;);",
"Identifier",
1
),
invalid(
"for ((let = []);;);",
"for (let = [];;);",
"AssignmentExpression",
1
),
invalid(
"for ((let) = [];;);",
"for (let = [];;);",
"Identifier",
1
),
invalid(
"for ((let());;);",
"for (let();;);",
"CallExpression",
1
),
invalid(
"for ((let([]));;);",
"for (let([]);;);",
"CallExpression",
1
),
invalid(
"for ((let())[a];;);",
"for (let()[a];;);",
"CallExpression",
1
),
invalid(
"for ((let`[]`);;);",
"for (let`[]`;;);",
"TaggedTemplateExpression",
1
),
invalid(
"for ((let.a);;);",
"for (let.a;;);",
"MemberExpression",
1
),
invalid(
"for ((let).a;;);",
"for (let.a;;);",
"Identifier",
1
),
invalid(
"for ((let).a = 1;;);",
"for (let.a = 1;;);",
"Identifier",
1
),
invalid(
"for ((let).a[b];;);",
"for (let.a[b];;);",
"Identifier",
1
),
invalid(
"for ((let.a)[b];;);",
"for (let.a[b];;);",
"MemberExpression",
1
),
invalid(
"for ((let.a[b]);;);",
"for (let.a[b];;);",
"MemberExpression",
1
),
invalid(
"for ((let);[];);",
"for (let;[];);",
"Identifier",
1
),
invalid(
"for (((let[a]));;);",
"for ((let[a]);;);",
"MemberExpression",
1
),
invalid(
"for (((let))[a];;);",
"for ((let)[a];;);",
"Identifier",
1
),
invalid(
"for (((let[a])).b;;);",
"for ((let[a]).b;;);",
"MemberExpression",
1
),
invalid(
"for (((let))[a].b;;);",
"for ((let)[a].b;;);",
"Identifier",
1
),
invalid(
"for (((let)[a]).b;;);",
"for ((let)[a].b;;);",
"MemberExpression",
1
),
invalid(
"for (((let[a]) = b);;);",
"for ((let[a]) = b;;);",
"AssignmentExpression",
1
),
invalid(
"for (((let)[a]) = b;;);",
"for ((let)[a] = b;;);",
"MemberExpression",
1
),
invalid(
"for (((let)[a] = b);;);",
"for ((let)[a] = b;;);",
"AssignmentExpression",
1
),
invalid(
"for ((Let[a]);;);",
"for (Let[a];;);",
"MemberExpression",
1
),
invalid(
"for ((lett)[a];;);",
"for (lett[a];;);",
"Identifier",
1
),
// ForInStatement#left expression cannot start with `let[`, but it can start with `let` if it isn't followed by `[`
invalid(
"for ((let) in foo);",
"for (let in foo);",
"Identifier",
1
),
invalid(
"for ((let())[a] in foo);",
"for (let()[a] in foo);",
"CallExpression",
1
),
invalid(
"for ((let.a) in foo);",
"for (let.a in foo);",
"MemberExpression",
1
),
invalid(
"for ((let).a in foo);",
"for (let.a in foo);",
"Identifier",
1
),
invalid(
"for ((let).a.b in foo);",
"for (let.a.b in foo);",
"Identifier",
1
),
invalid(
"for ((let).a[b] in foo);",
"for (let.a[b] in foo);",
"Identifier",
1
),
invalid(
"for ((let.a)[b] in foo);",
"for (let.a[b] in foo);",
"MemberExpression",
1
),
invalid(
"for ((let.a[b]) in foo);",
"for (let.a[b] in foo);",
"MemberExpression",
1
),
invalid(
"for (((let[a])) in foo);",
"for ((let[a]) in foo);",
"MemberExpression",
1
),
invalid(
"for (((let))[a] in foo);",
"for ((let)[a] in foo);",
"Identifier",
1
),
invalid(
"for (((let[a])).b in foo);",
"for ((let[a]).b in foo);",
"MemberExpression",
1
),
invalid(
"for (((let))[a].b in foo);",
"for ((let)[a].b in foo);",
"Identifier",
1
),
invalid(
"for (((let)[a]).b in foo);",
"for ((let)[a].b in foo);",
"MemberExpression",
1
),
invalid(
"for (((let[a]).b) in foo);",
"for ((let[a]).b in foo);",
"MemberExpression",
1
),
invalid(
"for ((Let[a]) in foo);",
"for (Let[a] in foo);",
"MemberExpression",
1
),
invalid(
"for ((lett)[a] in foo);",
"for (lett[a] in foo);",
"Identifier",
1
),
// ForOfStatement#left expression cannot start with `let`
invalid(
"for (((let)) of foo);",
"for ((let) of foo);",
"Identifier",
1
),
invalid(
"for (((let)).a of foo);",
"for ((let).a of foo);",
"Identifier",
1
),
invalid(
"for (((let))[a] of foo);",
"for ((let)[a] of foo);",
"Identifier",
1
),
invalid(
"for (((let).a) of foo);",
"for ((let).a of foo);",
"MemberExpression",
1
),
invalid(
"for (((let[a]).b) of foo);",
"for ((let[a]).b of foo);",
"MemberExpression",
1
),
invalid(
"for (((let).a).b of foo);",
"for ((let).a.b of foo);",
"MemberExpression",
1
),
invalid(
"for (((let).a.b) of foo);",
"for ((let).a.b of foo);",
"MemberExpression",
1
),
invalid(
"for (((let.a).b) of foo);",
"for ((let.a).b of foo);",
"MemberExpression",
1
),
invalid(
"for (((let()).a) of foo);",
"for ((let()).a of foo);",
"MemberExpression",
1
),
invalid(
"for ((Let) of foo);",
"for (Let of foo);",
"Identifier",
1
),
invalid(
"for ((lett) of foo);",
"for (lett of foo);",
"Identifier",
1
),
invalid("for (a in (b, c));", "for (a in b, c);", "SequenceExpression", null),
invalid(
"(let)",
"let",
"Identifier",
1
),
invalid(
"((let))",
"(let)",
"Identifier",
1
),
invalid("let s = `${(v)}`", "let s = `${v}`", "Identifier"),
invalid("let s = `${(a, b)}`", "let s = `${a, b}`", "SequenceExpression"),
invalid("function foo(a = (b)) {}", "function foo(a = b) {}", "Identifier"),
invalid("const bar = (a = (b)) => a", "const bar = (a = b) => a", "Identifier"),
invalid("const [a = (b)] = []", "const [a = b] = []", "Identifier"),
invalid("const {a = (b)} = {}", "const {a = b} = {}", "Identifier"),
// LHS of assignments/Assignment targets
invalid("(a) = b", "a = b", "Identifier"),
invalid("(a.b) = c", "a.b = c", "MemberExpression"),
invalid("(a) += b", "a += b", "Identifier"),
invalid("(a.b) >>= c", "a.b >>= c", "MemberExpression"),
invalid("[(a) = b] = []", "[a = b] = []", "Identifier"),
invalid("[(a.b) = c] = []", "[a.b = c] = []", "MemberExpression"),
invalid("({ a: (b) = c } = {})", "({ a: b = c } = {})", "Identifier"),
invalid("({ a: (b.c) = d } = {})", "({ a: b.c = d } = {})", "MemberExpression"),
invalid("[(a)] = []", "[a] = []", "Identifier"),
invalid("[(a.b)] = []", "[a.b] = []", "MemberExpression"),
invalid("[,(a),,] = []", "[,a,,] = []", "Identifier"),
invalid("[...(a)] = []", "[...a] = []", "Identifier"),
invalid("[...(a.b)] = []", "[...a.b] = []", "MemberExpression"),
invalid("({ a: (b) } = {})", "({ a: b } = {})", "Identifier"),
invalid("({ a: (b.c) } = {})", "({ a: b.c } = {})", "MemberExpression"),
invalid("({ ...(a) } = {})", "({ ...a } = {})", "Identifier"),
invalid("({ ...(a.b) } = {})", "({ ...a.b } = {})", "MemberExpression"),
// https://github.com/eslint/eslint/issues/11706 (also in valid[])
{
code: "for ((a = (b in c)); ;);",
output: "for ((a = b in c); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = ((b in c) && (d in e)); ;);",
output: "for (let a = (b in c && d in e); ;);",
errors: Array(2).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = ((b in c) in d); ;);",
output: "for (let a = (b in c in d); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b && (c in d)), e = (f in g); ;);",
output: "for (let a = (b && c in d), e = (f in g); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b + c), d = (e in f); ;);",
output: "for (let a = b + c, d = (e in f); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = [(b in c)]; ;);",
output: "for (let a = [b in c]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = [b, (c in d)]; ;);",
output: "for (let a = [b, c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = ([b in c]); ;);",
output: "for (let a = [b in c]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = ([b, c in d]); ;);",
output: "for (let a = [b, c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for ((a = [b in c]); ;);",
output: "for (a = [b in c]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = [b && (c in d)]; ;);",
output: "for (let a = [b && c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = [(b && c in d)]; ;);",
output: "for (let a = [b && c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = ([b && c in d]); ;);",
output: "for (let a = [b && c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for ((a = [b && c in d]); ;);",
output: "for (a = [b && c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for ([(a in b)]; ;);",
output: "for ([a in b]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (([a in b]); ;);",
output: "for ([a in b]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = [(b in c)], d = (e in f); ;);",
output: "for (let a = [b in c], d = (e in f); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let [a = (b in c)] = []; ;);",
output: "for (let [a = b in c] = []; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let [a = b && (c in d)] = []; ;);",
output: "for (let [a = b && c in d] = []; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = () => { (b in c) }; ;);",
output: "for (let a = () => { b in c }; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = () => { a && (b in c) }; ;);",
output: "for (let a = () => { a && b in c }; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = function () { (b in c) }; ;);",
output: "for (let a = function () { b in c }; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = { a: (b in c) }; ;);",
output: "for (let a = { a: b in c }; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = { a: b && (c in d) }; ;);",
output: "for (let a = { a: b && c in d }; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let { a = (b in c) } = {}; ;);",
output: "for (let { a = b in c } = {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let { a = b && (c in d) } = {}; ;);",
output: "for (let { a = b && c in d } = {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let { a: { b = c && (d in e) } } = {}; ;);",
output: "for (let { a: { b = c && d in e } } = {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = `${(a in b)}`; ;);",
output: "for (let a = `${a in b}`; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = `${a && (b in c)}`; ;);",
output: "for (let a = `${a && b in c}`; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b = (c in d)) => {}; ;);",
output: "for (let a = (b = c in d) => {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b = c && (d in e)) => {}; ;);",
output: "for (let a = (b = c && d in e) => {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b, c = d && (e in f)) => {}; ;);",
output: "for (let a = (b, c = d && e in f) => {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = function (b = c && (d in e)) {}; ;);",
output: "for (let a = function (b = c && d in e) {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = function (b, c = d && (e in f)) {}; ;);",
output: "for (let a = function (b, c = d && e in f) {}; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b((c in d)); ;);",
output: "for (let a = b(c in d); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b(c, (d in e)); ;);",
output: "for (let a = b(c, d in e); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b(c && (d in e)); ;);",
output: "for (let a = b(c && d in e); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b(c, d && (e in f)); ;);",
output: "for (let a = b(c, d && e in f); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = new b((c in d)); ;);",
output: "for (let a = new b(c in d); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = new b(c, (d in e)); ;);",
output: "for (let a = new b(c, d in e); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = new b(c && (d in e)); ;);",
output: "for (let a = new b(c && d in e); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = new b(c, d && (e in f)); ;);",
output: "for (let a = new b(c, d && e in f); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b[(c in d)]; ;);",
output: "for (let a = b[c in d]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b[c && (d in e)]; ;);",
output: "for (let a = b[c && d in e]; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b ? (c in d) : e; ;);",
output: "for (let a = b ? c in d : e; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = b ? c && (d in e) : f; ;);",
output: "for (let a = b ? c && d in e : f; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (a ? b && (c in d) : e; ;);",
output: "for (a ? b && c in d : e; ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = ((b in c)); ;);",
output: "for (let a = (b in c); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (((a in b)); ;);",
output: "for ((a in b); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (((a && b in c && d)); ;);",
output: "for ((a && b in c && d); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (!(b in c)); ;);",
output: "for (let a = !(b in c); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (!(b && c in d)); ;);",
output: "for (let a = !(b && c in d); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = !((b in c) && (d in e)); ;);",
output: "for (let a = !(b in c && d in e); ;);",
errors: Array(2).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = (x && (b in c)), d = () => { for ((e in f); ;); for ((g in h); ;); }; ;); for((i in j); ;);",
output: "for (let a = (x && b in c), d = () => { for ((e in f); ;); for ((g in h); ;); }; ;); for((i in j); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b in c), d = () => { for ((x && (e in f)); ;); for ((g in h); ;); }; ;); for((i in j); ;);",
output: "for (let a = (b in c), d = () => { for ((x && e in f); ;); for ((g in h); ;); }; ;); for((i in j); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b in c), d = () => { for ((e in f); ;); for ((x && (g in h)); ;); }; ;); for((i in j); ;);",
output: "for (let a = (b in c), d = () => { for ((e in f); ;); for ((x && g in h); ;); }; ;); for((i in j); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (b in c), d = () => { for ((e in f); ;); for ((g in h); ;); }; ;); for((x && (i in j)); ;);",
output: "for (let a = (b in c), d = () => { for ((e in f); ;); for ((g in h); ;); }; ;); for((x && i in j); ;);",
errors: [
{
messageId: "unexpected"
}
]
},
{
code: "for (let a = (x && (b in c)), d = () => { for ((e in f); ;); for ((y && (g in h)); ;); }; ;); for((i in j); ;);",
output: "for (let a = (x && b in c), d = () => { for ((e in f); ;); for ((y && g in h); ;); }; ;); for((i in j); ;);",
errors: Array(2).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = (x && (b in c)), d = () => { for ((y && (e in f)); ;); for ((z && (g in h)); ;); }; ;); for((w && (i in j)); ;);",
output: "for (let a = (x && b in c), d = () => { for ((y && e in f); ;); for ((z && g in h); ;); }; ;); for((w && i in j); ;);",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
// https://github.com/eslint/eslint/issues/11706 regression tests (also in valid[])
{
code: "for (let a = (b); a > (b); a = (b)) a = (b); a = (b);",
output: "for (let a = b; a > b; a = b) a = b; a = b;",
errors: Array(5).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for ((a = b); (a > b); (a = b)) (a = b); (a = b);",
output: "for (a = b; a > b; a = b) a = b; a = b;",
errors: Array(5).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = b; a > (b); a = (b)) a = (b); a = (b);",
output: "for (let a = b; a > b; a = b) a = b; a = b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = b; (a > b); (a = b)) (a = b); (a = b);",
output: "for (let a = b; a > b; a = b) a = b; a = b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (; a > (b); a = (b)) a = (b); a = (b);",
output: "for (; a > b; a = b) a = b; a = b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (; (a > b); (a = b)) (a = b); (a = b);",
output: "for (; a > b; a = b) a = b; a = b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = (b); a = (b in c); a = (b in c)) a = (b in c); a = (b in c);",
output: "for (let a = b; a = b in c; a = b in c) a = b in c; a = b in c;",
errors: Array(5).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = (b); (a in b); (a in b)) (a in b); (a in b);",
output: "for (let a = b; a in b; a in b) a in b; a in b;",
errors: Array(5).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = b; a = (b in c); a = (b in c)) a = (b in c); a = (b in c);",
output: "for (let a = b; a = b in c; a = b in c) a = b in c; a = b in c;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = b; (a in b); (a in b)) (a in b); (a in b);",
output: "for (let a = b; a in b; a in b) a in b; a in b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (; a = (b in c); a = (b in c)) a = (b in c); a = (b in c);",
output: "for (; a = b in c; a = b in c) a = b in c; a = b in c;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (; (a in b); (a in b)) (a in b); (a in b);",
output: "for (; a in b; a in b) a in b; a in b;",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
{
code: "for (let a = (b + c), d = () => { for ((e + f); ;); for ((g + h); ;); }; ;); for((i + j); ;);",
output: "for (let a = b + c, d = () => { for (e + f; ;); for (g + h; ;); }; ;); for(i + j; ;);",
errors: Array(4).fill(
{
messageId: "unexpected"
}
)
},
// import expressions
invalid(
"import((source))",
"import(source)",
"Identifier",
1,
{ parserOptions: { ecmaVersion: 2020 } }
),
invalid(
"import((source = 'foo.js'))",
"import(source = 'foo.js')",
"AssignmentExpression",
1,
{ parserOptions: { ecmaVersion: 2020 } }
),
invalid(
"import(((s,t)))",
"import((s,t))",
"SequenceExpression",
1,
{ parserOptions: { ecmaVersion: 2020 } }
),
// https://github.com/eslint/eslint/issues/12127
{
code: "[1, ((2, 3))];",
output: "[1, (2, 3)];",
errors: [{ messageId: "unexpected" }]
},
{
code: "const foo = () => ((bar, baz));",
output: "const foo = () => (bar, baz);",
errors: [{ messageId: "unexpected" }]
},
{
code: "foo = ((bar, baz));",
output: "foo = (bar, baz);",
errors: [{ messageId: "unexpected" }]
},
{
code: "foo + ((bar + baz));",
output: "foo + (bar + baz);",
errors: [{ messageId: "unexpected" }]
},
{
code: "((foo + bar)) + baz;",
output: "(foo + bar) + baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "foo * ((bar + baz));",
output: "foo * (bar + baz);",
errors: [{ messageId: "unexpected" }]
},
{
code: "((foo + bar)) * baz;",
output: "(foo + bar) * baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "new A(((foo, bar)))",
output: "new A((foo, bar))",
errors: [{ messageId: "unexpected" }]
},
{
code: "class A{ [((foo, bar))]() {} }",
output: "class A{ [(foo, bar)]() {} }",
errors: [{ messageId: "unexpected" }]
},
{
code: "new ((A, B))()",
output: "new (A, B)()",
errors: [{ messageId: "unexpected" }]
},
{
code: "((foo, bar)) ? bar : baz;",
output: "(foo, bar) ? bar : baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "((f ? o : o)) ? bar : baz;",
output: "(f ? o : o) ? bar : baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "((f = oo)) ? bar : baz;",
output: "(f = oo) ? bar : baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "foo ? ((bar, baz)) : baz;",
output: "foo ? (bar, baz) : baz;",
errors: [{ messageId: "unexpected" }]
},
{
code: "foo ? bar : ((bar, baz));",
output: "foo ? bar : (bar, baz);",
errors: [{ messageId: "unexpected" }]
},
{
code: "function foo(bar = ((baz1, baz2))) {}",
output: "function foo(bar = (baz1, baz2)) {}",
errors: [{ messageId: "unexpected" }]
},
{
code: "var foo = { bar: ((baz1, baz2)) };",
output: "var foo = { bar: (baz1, baz2) };",
errors: [{ messageId: "unexpected" }]
},
{
code: "var foo = { [((bar1, bar2))]: baz };",
output: "var foo = { [(bar1, bar2)]: baz };",
errors: [{ messageId: "unexpected" }]
},
// adjacent tokens tests for division operator, comments and regular expressions
invalid("a+/**/(/**/b)", "a+/**//**/b", "Identifier"),
invalid("a+/**/(//\nb)", "a+/**///\nb", "Identifier"),
invalid("a in(/**/b)", "a in/**/b", "Identifier"),
invalid("a in(//\nb)", "a in//\nb", "Identifier"),
invalid("a+(/**/b)", "a+/**/b", "Identifier"),
invalid("a+/**/(b)", "a+/**/b", "Identifier"),
invalid("a+(//\nb)", "a+//\nb", "Identifier"),
invalid("a+//\n(b)", "a+//\nb", "Identifier"),
invalid("a+(/^b$/)", "a+/^b$/", "Literal"),
invalid("a/(/**/b)", "a/ /**/b", "Identifier"),
invalid("a/(//\nb)", "a/ //\nb", "Identifier"),
invalid("a/(/^b$/)", "a/ /^b$/", "Literal"),
// Nullish coalescing
{
code: "var v = ((a ?? b)) || c",
output: "var v = (a ?? b) || c",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = a ?? ((b || c))",
output: "var v = a ?? (b || c)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = ((a ?? b)) && c",
output: "var v = (a ?? b) && c",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = a ?? ((b && c))",
output: "var v = a ?? (b && c)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = ((a || b)) ?? c",
output: "var v = (a || b) ?? c",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = a || ((b ?? c))",
output: "var v = a || (b ?? c)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = ((a && b)) ?? c",
output: "var v = (a && b) ?? c",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = a && ((b ?? c))",
output: "var v = a && (b ?? c)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = (a ?? b) ? b : c",
output: "var v = a ?? b ? b : c",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = (a | b) ?? c | d",
output: "var v = a | b ?? c | d",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = a | b ?? (c | d)",
output: "var v = a | b ?? c | d",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
// "allowParensAfterCommentPattern" option (off by default)
{
code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
options: ["all"],
errors: [{ messageId: "unexpected" }]
},
{
code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');",
options: ["all"],
errors: [{ messageId: "unexpected" }]
},
{
code: `
validate(/** @type {Schema} */ (schema), options, {
name: "Dev Server",
baseDataPath: "options",
});
`,
output: `
validate(/** @type {Schema} */ schema, options, {
name: "Dev Server",
baseDataPath: "options",
});
`,
options: ["all"],
errors: [{ messageId: "unexpected" }]
},
{
code: `
if (condition) {
/** @type {ServerOptions} */
(options.server.options).requestCert = false;
}
`,
output: `
if (condition) {
/** @type {ServerOptions} */
options.server.options.requestCert = false;
}
`,
options: ["all"],
errors: [{ messageId: "unexpected" }]
},
{
code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);",
options: ["all"],
errors: [{ messageId: "unexpected" }]
},
{
code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
errors: [{ messageId: "unexpected" }]
},
{
code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');",
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
errors: [{ messageId: "unexpected" }]
},
{
code: `
validate(/** @type {Schema} */ (schema), options, {
name: "Dev Server",
baseDataPath: "options",
});
`,
output: `
validate(/** @type {Schema} */ schema, options, {
name: "Dev Server",
baseDataPath: "options",
});
`,
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
errors: [{ messageId: "unexpected" }]
},
{
code: `
if (condition) {
/** @type {ServerOptions} */
(options.server.options).requestCert = false;
}
`,
output: `
if (condition) {
/** @type {ServerOptions} */
options.server.options.requestCert = false;
}
`,
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
errors: [{ messageId: "unexpected" }]
},
{
code: `
if (condition) {
/** @type {ServerOptions} */
/** extra comment */
(options.server.options).requestCert = false;
}
`,
output: `
if (condition) {
/** @type {ServerOptions} */
/** extra comment */
options.server.options.requestCert = false;
}
`,
options: ["all", { allowParensAfterCommentPattern: "@type" }],
errors: [{ messageId: "unexpected" }]
},
{
code: `
if (condition) {
/** @type {ServerOptions} */
((options.server.options)).requestCert = false;
}
`,
output: `
if (condition) {
/** @type {ServerOptions} */
(options.server.options).requestCert = false;
}
`,
options: ["all", { allowParensAfterCommentPattern: "@type" }],
errors: [{ messageId: "unexpected" }]
},
{
code: `
if (condition) {
/** @type {ServerOptions} */
let foo = "bar";
(options.server.options).requestCert = false;
}
`,
output: `
if (condition) {
/** @type {ServerOptions} */
let foo = "bar";
options.server.options.requestCert = false;
}
`,
options: ["all", { allowParensAfterCommentPattern: "@type" }],
errors: [{ messageId: "unexpected" }]
},
{
code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);",
options: ["all", { allowParensAfterCommentPattern: "invalid" }],
errors: [{ messageId: "unexpected" }]
},
// Optional chaining
{
code: "var v = (obj?.aaa)?.aaa",
output: "var v = obj?.aaa?.aaa",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var v = (obj.aaa)?.aaa",
output: "var v = obj.aaa?.aaa",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var foo = (function(){})?.call()",
output: "var foo = function(){}?.call()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "var foo = (function(){}?.call())",
output: "var foo = function(){}?.call()",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
{
code: "(Object.prototype.toString.call())",
output: "Object.prototype.toString.call()",
options: ["all"],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
},
// https://github.com/eslint/eslint/issues/16850
invalid("(a) = function foo() {};", "a = function foo() {};", "Identifier"),
invalid("(a) = class Bar {};", "a = class Bar {};", "Identifier"),
invalid("(a.b) = function () {};", "a.b = function () {};", "MemberExpression"),
{
code: "(newClass) = [(one)] = class { static * [Symbol.iterator]() { yield 1; } };",
output: "newClass = [one] = class { static * [Symbol.iterator]() { yield 1; } };",
errors: [
{ messageId: "unexpected", type: "Identifier" },
{ messageId: "unexpected", type: "Identifier" }
]
},
invalid("((a)) = () => {};", "(a) = () => {};", "Identifier"),
invalid("(a) = (function () {})();", "a = (function () {})();", "Identifier"),
...["**=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|="].map(
operator => invalid(
`(a) ${operator} function () {};`,
`a ${operator} function () {};`,
"Identifier"
)
)
]
});