Skip to content

Commit

Permalink
Fix: arrow-body-style fixer for in wrap (fixes #11849) (#13228)
Browse files Browse the repository at this point in the history
* Fix: add parens when in operator (fixes #11849)

* Chore: some more tests

* Chore: update jsdoc comments

Co-authored-by: YeonJuan <yeonjuan93@naver.com>

* Update: add paren only for ForStatement

* Update: fixed adding extra parens

* Update: minified traversing using visitor query

* Chore: isInOp to false while existing

* Update: fixed the logic

* Update: logic

* Update: checking inside of for loop

* Chore: updated is for in check

Co-authored-by: YeonJuan <yeonjuan93@naver.com>
  • Loading branch information
anikethsaha and yeonjuan committed Jul 11, 2020
1 parent 748734f commit a96bc5e
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 10 deletions.
47 changes: 41 additions & 6 deletions lib/rules/arrow-body-style.js
Expand Up @@ -75,6 +75,7 @@ module.exports = {
const never = options[0] === "never";
const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
const sourceCode = context.getSourceCode();
let funcInfo = null;

/**
* Checks whether the given node has ASI problem or not.
Expand All @@ -99,6 +100,21 @@ module.exports = {
return sourceCode.getTokenAfter(node);
}

/**
* Check whether the node is inside of a for loop's init
* @param {ASTNode} node node is inside for loop
* @returns {boolean} `true` if the node is inside of a for loop, else `false`
*/
function isInsideForLoopInitializer(node) {
if (node && node.parent) {
if (node.parent.type === "ForStatement" && node.parent.init === node) {
return true;
}
return isInsideForLoopInitializer(node.parent);
}
return false;
}

/**
* Determines whether a arrow function body needs braces
* @param {ASTNode} node The arrow function node.
Expand Down Expand Up @@ -178,11 +194,13 @@ module.exports = {
* If the first token of the reutrn value is `{` or the return value is a sequence expression,
* enclose the return value by parentheses to avoid syntax error.
*/
if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression") {
fixes.push(
fixer.insertTextBefore(firstValueToken, "("),
fixer.insertTextAfter(lastValueToken, ")")
);
if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression" || (funcInfo.hasInOperator && isInsideForLoopInitializer(node))) {
if (!astUtils.isParenthesised(sourceCode, blockBody[0].argument)) {
fixes.push(
fixer.insertTextBefore(firstValueToken, "("),
fixer.insertTextAfter(lastValueToken, ")")
);
}
}

/*
Expand Down Expand Up @@ -245,7 +263,24 @@ module.exports = {
}

return {
"ArrowFunctionExpression:exit": validate
"BinaryExpression[operator='in']"() {
let info = funcInfo;

while (info) {
info.hasInOperator = true;
info = info.upper;
}
},
ArrowFunctionExpression() {
funcInfo = {
upper: funcInfo,
hasInOperator: false
};
},
"ArrowFunctionExpression:exit"(node) {
validate(node);
funcInfo = funcInfo.upper;
}
};
}
};
242 changes: 238 additions & 4 deletions tests/lib/rules/arrow-body-style.js
Expand Up @@ -45,6 +45,239 @@ ruleTester.run("arrow-body-style", rule, {
{ code: "var foo = () => { return { bar: 0 }; };", options: ["as-needed", { requireReturnForObjectLiteral: true }] }
],
invalid: [
{
code: "for (var foo = () => { return a in b ? bar : () => {} } ;;);",
output: "for (var foo = () => (a in b ? bar : () => {}) ;;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 22,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "a in b; for (var f = () => { return c };;);",
output: "a in b; for (var f = () => c;;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 28,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (a = b => { return c in d ? e : f } ;;);",
output: "for (a = b => (c in d ? e : f) ;;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 15,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (var f = () => { return a };;);",
output: "for (var f = () => a;;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 20,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (var f;f = () => { return a };);",
output: "for (var f;f = () => a;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 22,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (var f = () => { return a in c };;);",
output: "for (var f = () => (a in c);;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 20,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (var f;f = () => { return a in c };);",
output: "for (var f;f = () => a in c;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 22,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (;;){var f = () => { return a in c }}",
output: "for (;;){var f = () => a in c}",
options: ["as-needed"],
errors: [
{
line: 1,
column: 24,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (a = b => { return c = d in e } ;;);",
output: "for (a = b => (c = d in e) ;;);",
options: ["as-needed"],
errors: [
{
line: 1,
column: 15,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (var a;;a = b => { return c = d in e } );",
output: "for (var a;;a = b => c = d in e );",
options: ["as-needed"],
errors: [
{
line: 1,
column: 22,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (let a = (b, c, d) => { return vb && c in d; }; ;);",
output: "for (let a = (b, c, d) => (vb && c in d); ;);",
errors: [
{
line: 1,
column: 27,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (let a = (b, c, d) => { return v in b && c in d; }; ;);",
output: "for (let a = (b, c, d) => (v in b && c in d); ;);",
errors: [
{
line: 1,
column: 27,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "function foo(){ for (let a = (b, c, d) => { return v in b && c in d; }; ;); }",
output: "function foo(){ for (let a = (b, c, d) => (v in b && c in d); ;); }",
errors: [
{
line: 1,
column: 43,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for ( a = (b, c, d) => { return v in b && c in d; }; ;);",
output: "for ( a = (b, c, d) => (v in b && c in d); ;);",
errors: [
{
line: 1,
column: 24,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for ( a = (b) => { return (c in d) }; ;);",
output: "for ( a = (b) => (c in d); ;);",
errors: [
{
line: 1,
column: 18,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (let a = (b, c, d) => { return vb in dd ; }; ;);",
output: "for (let a = (b, c, d) => (vb in dd ); ;);",
errors: [
{
line: 1,
column: 27,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "for (let a = (b, c, d) => { return vb in c in dd ; }; ;);",
output: "for (let a = (b, c, d) => (vb in c in dd ); ;);",
errors: [
{
line: 1,
column: 27,
messageId: "unexpectedSingleBlock"
}
]
},
{
code: "do{let a = () => {return f in ff}}while(true){}",
output: "do{let a = () => f in ff}while(true){}",
errors: [{
line: 1,
column: 18,
messageId: "unexpectedSingleBlock"
}]
},
{
code: "do{for (let a = (b, c, d) => { return vb in c in dd ; }; ;);}while(true){}",
output: "do{for (let a = (b, c, d) => (vb in c in dd ); ;);}while(true){}",
errors: [{
line: 1,
column: 30,
messageId: "unexpectedSingleBlock"
}]
},
{
code: "scores.map(score => { return x in +(score / maxScore).toFixed(2)});",
output: "scores.map(score => x in +(score / maxScore).toFixed(2));",
errors: [{
line: 1,
column: 21,
messageId: "unexpectedSingleBlock"
}]
},
{
code: "const fn = (a, b) => { return a + x in Number(b) };",
output: "const fn = (a, b) => a + x in Number(b);",
errors: [{
line: 1,
column: 22,
messageId: "unexpectedSingleBlock"
}]
},
{
code: "var foo = () => 0",
output: "var foo = () => {return 0}",
Expand Down Expand Up @@ -370,8 +603,8 @@ ruleTester.run("arrow-body-style", rule, {

// Not fixed; fixing would cause ASI issues.
code:
"var foo = () => { return bar }\n" +
"[1, 2, 3].map(foo)",
"var foo = () => { return bar }\n" +
"[1, 2, 3].map(foo)",
output: null,
options: ["never"],
errors: [
Expand All @@ -380,10 +613,11 @@ ruleTester.run("arrow-body-style", rule, {
},
{


// Not fixed; fixing would cause ASI issues.
code:
"var foo = () => { return bar }\n" +
"(1).toString();",
"var foo = () => { return bar }\n" +
"(1).toString();",
output: null,
options: ["never"],
errors: [
Expand Down

0 comments on commit a96bc5e

Please sign in to comment.