From 44954824e7e1d36ae4a9760f3952d083e290f14e Mon Sep 17 00:00:00 2001 From: dios Date: Thu, 28 Jun 2018 17:39:17 -0700 Subject: [PATCH 01/24] Add and pass for a test case for when a comment exists between an arrow and expression body in implicit-arrow-linebreak --- lib/rules/implicit-arrow-linebreak.js | 21 ++++++++++++++++++++- tests/lib/rules/implicit-arrow-linebreak.js | 10 ++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index a7ad1122b50..a7a2afd2b49 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -72,7 +72,26 @@ module.exports = { context.report({ node: fixerTarget, message: "Expected no linebreak before this expression.", - fix: fixer => fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ") + fix: fixer => { + const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); + const comments = sourceCode.getCommentsAfter(tokenBefore); + const hasComments = comments.length > 0; + + if (hasComments) { + const { value, type } = comments[0]; + + const text = type === 'Line' ? `//${value}` : `/*${value}*/`; + + const firstToken = sourceCode.getFirstToken(node); + + const commentBeforeExpression = fixer.insertTextBeforeRange( + firstToken.range, + text + '\n'); + + return [placeBesides, commentBeforeExpression]; + } + return placeBesides; + } }); } } diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 7212e083f1b..a018e3a7ce8 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -132,6 +132,16 @@ ruleTester.run("implicit-arrow-linebreak", rule, { ) `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + (foo) => + // test comment + bar + `, + output: ` + // test comment\n(foo) => bar + `, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From 7b9bdf462e27811a7f938f285ebdab427346ef58 Mon Sep 17 00:00:00 2001 From: dios Date: Thu, 28 Jun 2018 17:47:51 -0700 Subject: [PATCH 02/24] Fix formatting --- lib/rules/implicit-arrow-linebreak.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index a7a2afd2b49..30a75719508 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -80,13 +80,14 @@ module.exports = { if (hasComments) { const { value, type } = comments[0]; - const text = type === 'Line' ? `//${value}` : `/*${value}*/`; + const text = type === "Line" ? `//${value}` : `/*${value}*/`; const firstToken = sourceCode.getFirstToken(node); const commentBeforeExpression = fixer.insertTextBeforeRange( firstToken.range, - text + '\n'); + `${text}\n` + ); return [placeBesides, commentBeforeExpression]; } From fd31e1834c77fd23af7368ebecad5bf9e6775002 Mon Sep 17 00:00:00 2001 From: dios Date: Thu, 28 Jun 2018 18:30:28 -0700 Subject: [PATCH 03/24] Add and pass test case for when arrow expression is set to variable --- lib/rules/implicit-arrow-linebreak.js | 10 +++++++--- tests/lib/rules/implicit-arrow-linebreak.js | 10 ++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 30a75719508..2380957ead1 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -82,10 +82,14 @@ module.exports = { const text = type === "Line" ? `//${value}` : `/*${value}*/`; - const firstToken = sourceCode.getFirstToken(node); + let firstToken = sourceCode.getFirstToken(node); - const commentBeforeExpression = fixer.insertTextBeforeRange( - firstToken.range, + if (node.parent.type === 'VariableDeclarator') { + firstToken = sourceCode.getFirstToken(node.parent.parent); + } + + const commentBeforeExpression = fixer.insertTextBefore( + firstToken, `${text}\n` ); diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index a018e3a7ce8..6e82c32e298 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -142,6 +142,16 @@ ruleTester.run("implicit-arrow-linebreak", rule, { // test comment\n(foo) => bar `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + const foo = () => + // comment + [] + `, + output: ` + // comment\nconst foo = () => [] + `, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From 1d216a54630012c14083d011636a9b00e98792fc Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 13:22:28 -0700 Subject: [PATCH 04/24] Add test cases for when comments exist within parens enwrapped arrow function bodies, pass cases --- lib/rules/implicit-arrow-linebreak.js | 10 ++++- tests/lib/rules/implicit-arrow-linebreak.js | 43 ++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 2380957ead1..9d3f307fdbc 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -74,7 +74,8 @@ module.exports = { message: "Expected no linebreak before this expression.", fix: fixer => { const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); - const comments = sourceCode.getCommentsAfter(tokenBefore); + const comments = sourceCode.getCommentsInside(node); + const hasComments = comments.length > 0; if (hasComments) { @@ -93,8 +94,15 @@ module.exports = { `${text}\n` ); + if (fixerTarget.value === '(') { + if (comments[0].loc.start.line > fixerTarget.loc.start.line) { + return placeBesides; + } + } + return [placeBesides, commentBeforeExpression]; } + return placeBesides; } }); diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 6e82c32e298..e1975bd382d 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -76,7 +76,7 @@ ruleTester.run("implicit-arrow-linebreak", rule, { baz; `, options: ["below"] - } + }, ], invalid: [ @@ -152,6 +152,47 @@ ruleTester.run("implicit-arrow-linebreak", rule, { // comment\nconst foo = () => [] `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + (foo) => + ( + //comment + bar + ) + `, + output: ` + (foo) => ( + //comment + bar + ) + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + (foo) => + ( + bar + //comment + ) + + `, + output: ` + (foo) => ( + bar + //comment + ) + + `, + errors: [UNEXPECTED_LINEBREAK] + + }, { + code: `() => // comment \n bar`, + output: `// comment \n() => bar`, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: `(foo) => //comment \n bar`, + output: `//comment \n(foo) => bar`, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From f1d6e09ad257539e67b9cba17e561b450a932d36 Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 17:37:38 -0700 Subject: [PATCH 05/24] Add test cases for block comments, multiple comments within an arrow expression, pass test cases, create helper for formatting comments --- lib/rules/implicit-arrow-linebreak.js | 44 +++++++++++++-------- tests/lib/rules/implicit-arrow-linebreak.js | 28 ++++++++++--- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 9d3f307fdbc..a5f7b131d26 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -37,6 +37,22 @@ module.exports = { return context.options[0] || "beside"; } + /** + * Formats the comments depending on whether it's a line or block comment. + * @param {Comment[]} comments The array of comments inside the node + * @returns {string} A string of comment text joined by line breaks + */ + function formatComments(comments) { + return comments.map(comment => { + + if (comment.type === "Line") { + return `//${comment.value}`; + } + + return `/*${comment.value}*/`; + }).join("\n"); + } + /** * Validates the location of an arrow function body * @param {ASTNode} node The arrow function body @@ -49,7 +65,7 @@ module.exports = { let tokenBefore = sourceCode.getTokenBefore(node.body); const hasParens = tokenBefore.value === "("; - if (node.type === "BlockStatement") { + if (node.body.type === "BlockStatement") { return; } @@ -73,34 +89,30 @@ module.exports = { node: fixerTarget, message: "Expected no linebreak before this expression.", fix: fixer => { - const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); - const comments = sourceCode.getCommentsInside(node); - - const hasComments = comments.length > 0; - - if (hasComments) { - const { value, type } = comments[0]; + const placeBesides = [fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ")]; - const text = type === "Line" ? `//${value}` : `/*${value}*/`; + const comments = sourceCode.getCommentsInside(node); - let firstToken = sourceCode.getFirstToken(node); + if (comments.length > 0) { + const firstToken = sourceCode.getFirstToken( + node.parent.type === "VariableDeclarator" + ? node.parent.parent : node + ); - if (node.parent.type === 'VariableDeclarator') { - firstToken = sourceCode.getFirstToken(node.parent.parent); - } + const commentText = formatComments(comments); const commentBeforeExpression = fixer.insertTextBefore( firstToken, - `${text}\n` + `${commentText}\n` ); - if (fixerTarget.value === '(') { + if (fixerTarget.value === "(") { if (comments[0].loc.start.line > fixerTarget.loc.start.line) { return placeBesides; } } - return [placeBesides, commentBeforeExpression]; + return [...placeBesides, commentBeforeExpression]; } return placeBesides; diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index e1975bd382d..b4a9ac88305 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -76,7 +76,7 @@ ruleTester.run("implicit-arrow-linebreak", rule, { baz; `, options: ["below"] - }, + } ], invalid: [ @@ -186,12 +186,30 @@ ruleTester.run("implicit-arrow-linebreak", rule, { errors: [UNEXPECTED_LINEBREAK] }, { - code: `() => // comment \n bar`, - output: `// comment \n() => bar`, + code: `(foo) => + // comment + // another comment + bar`, + output: "// comment\n// another comment\n(foo) => bar", + errors: [UNEXPECTED_LINEBREAK] + }, + { + code: "() => // comment \n bar", + output: "// comment \n() => bar", + errors: [UNEXPECTED_LINEBREAK] + }, { + code: "(foo) => //comment \n bar", + output: "//comment \n(foo) => bar", errors: [UNEXPECTED_LINEBREAK] }, { - code: `(foo) => //comment \n bar`, - output: `//comment \n(foo) => bar`, + code: ` + (foo) => + /* test comment */ + bar + `, + output: ` + /* test comment */\n(foo) => bar + `, errors: [UNEXPECTED_LINEBREAK] }, From 41f3ec47f66b5b64c1f0aa4b22d68e6675459303 Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 17:56:35 -0700 Subject: [PATCH 06/24] Add a test case to ensure filtering of comments between start of arrow expression and parens --- lib/rules/implicit-arrow-linebreak.js | 11 +++++++---- tests/lib/rules/implicit-arrow-linebreak.js | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index a5f7b131d26..7e14d23c212 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -65,7 +65,7 @@ module.exports = { let tokenBefore = sourceCode.getTokenBefore(node.body); const hasParens = tokenBefore.value === "("; - if (node.body.type === "BlockStatement") { + if (node.type === "BlockStatement") { return; } @@ -89,7 +89,7 @@ module.exports = { node: fixerTarget, message: "Expected no linebreak before this expression.", fix: fixer => { - const placeBesides = [fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ")]; + const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); const comments = sourceCode.getCommentsInside(node); @@ -99,7 +99,10 @@ module.exports = { ? node.parent.parent : node ); - const commentText = formatComments(comments); + const commentText = formatComments( + comments + .filter(comment => comment.loc.start.line < fixerTarget.loc.start.line) + ); const commentBeforeExpression = fixer.insertTextBefore( firstToken, @@ -112,7 +115,7 @@ module.exports = { } } - return [...placeBesides, commentBeforeExpression]; + return [placeBesides, commentBeforeExpression]; } return placeBesides; diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index b4a9ac88305..78ac3f881f8 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -192,6 +192,18 @@ ruleTester.run("implicit-arrow-linebreak", rule, { bar`, output: "// comment\n// another comment\n(foo) => bar", errors: [UNEXPECTED_LINEBREAK] + }, { + code: `(foo) => + // comment + ( + // another comment + bar + )`, + output: `// comment\n(foo) => ( + // another comment + bar + )`, + errors: [UNEXPECTED_LINEBREAK] }, { code: "() => // comment \n bar", From b4186049e89462434a16c57e6a2317dca6c33a15 Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 18:33:43 -0700 Subject: [PATCH 07/24] Change condition to check for length of comment text length --- lib/rules/implicit-arrow-linebreak.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 7e14d23c212..8e500d28e70 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -109,10 +109,8 @@ module.exports = { `${commentText}\n` ); - if (fixerTarget.value === "(") { - if (comments[0].loc.start.line > fixerTarget.loc.start.line) { - return placeBesides; - } + if (commentText.length === 0) { + return placeBesides; } return [placeBesides, commentBeforeExpression]; From 1f03b1823efe6f81f4b1f8fb9aadc6e63b26c288 Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 18:50:24 -0700 Subject: [PATCH 08/24] Condense logic for comments filtering --- lib/rules/implicit-arrow-linebreak.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 8e500d28e70..a2dd8dfb38f 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -91,7 +91,7 @@ module.exports = { fix: fixer => { const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); - const comments = sourceCode.getCommentsInside(node); + const comments = sourceCode.getCommentsInside(node).filter(comment => comment.loc.start.line < fixerTarget.loc.start.line); if (comments.length > 0) { const firstToken = sourceCode.getFirstToken( @@ -99,20 +99,13 @@ module.exports = { ? node.parent.parent : node ); - const commentText = formatComments( - comments - .filter(comment => comment.loc.start.line < fixerTarget.loc.start.line) - ); + const commentText = formatComments(comments); const commentBeforeExpression = fixer.insertTextBefore( firstToken, `${commentText}\n` ); - if (commentText.length === 0) { - return placeBesides; - } - return [placeBesides, commentBeforeExpression]; } From d1f1a432950796cdc1e42db2d1a110580f51cafd Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 29 Jun 2018 18:52:59 -0700 Subject: [PATCH 09/24] Reword documentation for helper function --- lib/rules/implicit-arrow-linebreak.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index a2dd8dfb38f..37b1844d8fb 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -39,7 +39,7 @@ module.exports = { /** * Formats the comments depending on whether it's a line or block comment. - * @param {Comment[]} comments The array of comments inside the node + * @param {Comment[]} comments The array of comments between the arrow and body * @returns {string} A string of comment text joined by line breaks */ function formatComments(comments) { From e6098d1d2838b303bc2cf4f1d10d4b2c0097def7 Mon Sep 17 00:00:00 2001 From: dios Date: Mon, 2 Jul 2018 17:48:27 -0700 Subject: [PATCH 10/24] Account for multi arrow function test case with comments for implicit-arrow-linebreak, begin implementation for condition --- lib/rules/implicit-arrow-linebreak.js | 31 +++++++++++++++++++-- tests/lib/rules/implicit-arrow-linebreak.js | 18 ++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 37b1844d8fb..a73f298a91f 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -78,6 +78,8 @@ module.exports = { fixerTarget = sourceCode.getTokenAfter(tokenBefore); } + const comments = sourceCode.getCommentsInside(node).filter(comment => comment.loc.start.line < fixerTarget.loc.start.line); + if (tokenBefore.loc.end.line === fixerTarget.loc.start.line && option === "below") { context.report({ node: fixerTarget, @@ -91,9 +93,34 @@ module.exports = { fix: fixer => { const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); - const comments = sourceCode.getCommentsInside(node).filter(comment => comment.loc.start.line < fixerTarget.loc.start.line); - if (comments.length > 0) { + if (node.body.type === "ArrowFunctionExpression" || + node.parent.type === "ArrowFunctionExpression") { + + const parensFixer = [ + fixer.insertTextAfter(tokenBefore, " (") + ]; + + if (node.body.type === "Identifier") { + let output = ""; + let currParent = node; + + do { + const whiteSpaces = " ".repeat(currParent.params[0].loc.start.column); + + output += `\n${whiteSpaces})`; + + currParent = currParent.parent; + } while (currParent.type === "ArrowFunctionExpression"); + + const lastToken = sourceCode.getLastToken(fixerTarget); + + return [...parensFixer, fixer.insertTextAfter(lastToken, output)]; + } + + return parensFixer; + } + const firstToken = sourceCode.getFirstToken( node.parent.type === "VariableDeclarator" ? node.parent.parent : node diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 78ac3f881f8..e2b46233b6b 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -223,6 +223,24 @@ ruleTester.run("implicit-arrow-linebreak", rule, { /* test comment */\n(foo) => bar `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + (foo) => + // hi + bar => + // there + baz; + `, + output: ` + (foo) => ( + // hi + bar => ( + // there + baz + ) + ); + `, + errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] }, // 'below' option From 7ddaa0c705b129d9ee334ad2096e90ead942aef2 Mon Sep 17 00:00:00 2001 From: dios Date: Fri, 6 Jul 2018 19:34:40 -0700 Subject: [PATCH 11/24] Add test case for when some arrow function bodies are wrapped with parens, add logic to account for test case --- lib/rules/implicit-arrow-linebreak.js | 44 +++++++++++++++++---- tests/lib/rules/implicit-arrow-linebreak.js | 19 +++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index a73f298a91f..42e777f26d4 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -4,6 +4,8 @@ */ "use strict"; +const astUtils = require("../ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -94,13 +96,43 @@ module.exports = { const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); if (comments.length > 0) { - if (node.body.type === "ArrowFunctionExpression" || - node.parent.type === "ArrowFunctionExpression") { + const parensFixer = [ + fixer.insertTextAfter(tokenBefore, " (") + ]; + + if (node.body.type === "ArrowFunctionExpression" && node.parent.parent.type === "Program") { + let currBody = node; + let arrowCount = 0; + let needParens = 0; + let output = ""; + + do { + if (!sourceCode.getFirstTokenBetween( + currBody.params[currBody.params.length - 1], + currBody.body, + astUtils.isOpeningParenToken + )) { + const whiteSpaces = " ".repeat(currBody.params[0].loc.start.column); + output = `\n${whiteSpaces})` + output; + + needParens++; + } + + arrowCount++; + currBody = currBody.body; + } while (currBody.type === "ArrowFunctionExpression"); + + if (arrowCount !== needParens) { + + const lastToken = sourceCode.getLastToken(fixerTarget); - const parensFixer = [ - fixer.insertTextAfter(tokenBefore, " (") - ]; + return [...parensFixer, + fixer.insertTextAfter(lastToken, output) + ]; + } + return parensFixer; + } else if (node.parent.type === "ArrowFunctionExpression") { if (node.body.type === "Identifier") { let output = ""; let currParent = node; @@ -117,8 +149,6 @@ module.exports = { return [...parensFixer, fixer.insertTextAfter(lastToken, output)]; } - - return parensFixer; } const firstToken = sourceCode.getFirstToken( diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index e2b46233b6b..454592962e4 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -241,6 +241,25 @@ ruleTester.run("implicit-arrow-linebreak", rule, { ); `, errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] + }, { + code: ` + (foo) => + // hi + bar => ( + // there + baz + ) + `, + output: ` + (foo) => ( + // hi + bar => ( + // there + baz + ) + ) + `, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From 5d63f7141cef16c5af6a1b5232420252bceb70b3 Mon Sep 17 00:00:00 2001 From: dios Date: Mon, 9 Jul 2018 15:50:01 -0700 Subject: [PATCH 12/24] Export fixer logic for besides to autoFixBesides function, account for test cases with nested arrow functions, specify astutil functions in implicit arrow linebreak --- lib/rules/implicit-arrow-linebreak.js | 190 +++++++++++++++----------- 1 file changed, 109 insertions(+), 81 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 42e777f26d4..5fe0dad04e1 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -4,7 +4,11 @@ */ "use strict"; -const astUtils = require("../ast-utils"); +const { + isArrowToken, + isParenthesised, + isOpeningParenToken +} = require("../ast-utils");; //------------------------------------------------------------------------------ // Rule Definition @@ -45,14 +49,115 @@ module.exports = { * @returns {string} A string of comment text joined by line breaks */ function formatComments(comments) { - return comments.map(comment => { + + + return `${comments.map(comment => { if (comment.type === "Line") { return `//${comment.value}`; } return `/*${comment.value}*/`; - }).join("\n"); + }).join(`\n${whiteSpaces}`)}\n${whiteSpaces}`; + } + + /** + * Finds the first token depending on the parent type + * @param {Node} node The validated node + * @returns {Token|Node} The node to prepend comments to + */ + function findFirstToken(node) { + switch (node.parent.type) { + case "VariableDeclarator": + return sourceCode.getFirstToken(node.parent.parent); + case "CallExpression": + case "Property": + return sourceCode.getFirstToken(node.parent); + default: + return node; + } + } + + /** + * Helper function for adding parentheses fixes for nodes containing nested arrow functions + * @param {Fixer} fixer Fixer + * @param {Token} arrow - The arrow token + * @param {ASTNode} fixerTarget - The arrow function body + * @returns {Function[]} autofixer -- wraps function bodies with parentheses + */ + function addParentheses(fixer, arrow, fixerTarget) { + const parenthesesFixes = []; + let closingParentheses = ""; + + let followingBody; + + let currentArrow = arrow; + + while (currentArrow) { + followingBody = sourceCode.getTokenAfter(currentArrow, token => !isOpeningParenToken(token)); + + if (!isParenthesised(sourceCode, followingBody)) { + parenthesesFixes.push( + fixer.insertTextAfter(currentArrow, " (") + ); + + const paramsToken = sourceCode.getTokenBefore(currentArrow, token => + isOpeningParenToken(token) || token.type === "Identifier"); + + const whiteSpaces = " ".repeat(paramsToken.loc.start.column); + + closingParentheses = `\n${whiteSpaces})${closingParentheses}`; + } + + currentArrow = sourceCode.getTokenAfter(currentArrow, isArrowToken); + } + + return [...parenthesesFixes, + fixer.insertTextAfter(fixerTarget, closingParentheses) + ]; + } + + /** + * Autofixes the function body to collapse onto the same line as the arrow. + * If comments exist, prepends the comments before the arrow function. + * If the function body contains arrow functions, appends the function bodies with parentheses. + * @param {Token} arrow The arrow token. + * @param {ASTNode} fixerTarget the function body + * @param {ASTNode} node The node + * @returns {Function} autofixer -- validates the node to adhere to besides + */ + function autoFixBesides(arrow, fixerTarget, node) { + return fixer => { + const placeBesides = fixer.replaceTextRange([arrow.range[1], fixerTarget.range[0]], " "); + + const comments = sourceCode.getCommentsInside(node).filter(comment => + comment.loc.start.line < fixerTarget.loc.start.line); + + if (comments.length) { + + const precedingArrow = sourceCode.getTokenBefore(arrow, isArrowToken); + + // Check if any arrow functions follow + if (sourceCode.getTokenAfter(arrow, isArrowToken)) { + return addParentheses(fixer, arrow, fixerTarget); + } + + if (precedingArrow) { + return null; + } + + const commentText = formatComments(comments); + + const commentBeforeExpression = fixer.insertTextBeforeRange( + sourceCode.ast.tokens[0].range, + `${commentText}\n` + ); + + return [placeBesides, commentBeforeExpression]; + } + + return placeBesides; + }; } /** @@ -80,8 +185,6 @@ module.exports = { fixerTarget = sourceCode.getTokenAfter(tokenBefore); } - const comments = sourceCode.getCommentsInside(node).filter(comment => comment.loc.start.line < fixerTarget.loc.start.line); - if (tokenBefore.loc.end.line === fixerTarget.loc.start.line && option === "below") { context.report({ node: fixerTarget, @@ -92,82 +195,7 @@ module.exports = { context.report({ node: fixerTarget, message: "Expected no linebreak before this expression.", - fix: fixer => { - const placeBesides = fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " "); - - if (comments.length > 0) { - const parensFixer = [ - fixer.insertTextAfter(tokenBefore, " (") - ]; - - if (node.body.type === "ArrowFunctionExpression" && node.parent.parent.type === "Program") { - let currBody = node; - let arrowCount = 0; - let needParens = 0; - let output = ""; - - do { - if (!sourceCode.getFirstTokenBetween( - currBody.params[currBody.params.length - 1], - currBody.body, - astUtils.isOpeningParenToken - )) { - const whiteSpaces = " ".repeat(currBody.params[0].loc.start.column); - output = `\n${whiteSpaces})` + output; - - needParens++; - } - - arrowCount++; - currBody = currBody.body; - } while (currBody.type === "ArrowFunctionExpression"); - - if (arrowCount !== needParens) { - - const lastToken = sourceCode.getLastToken(fixerTarget); - - return [...parensFixer, - fixer.insertTextAfter(lastToken, output) - ]; - } - - return parensFixer; - } else if (node.parent.type === "ArrowFunctionExpression") { - if (node.body.type === "Identifier") { - let output = ""; - let currParent = node; - - do { - const whiteSpaces = " ".repeat(currParent.params[0].loc.start.column); - - output += `\n${whiteSpaces})`; - - currParent = currParent.parent; - } while (currParent.type === "ArrowFunctionExpression"); - - const lastToken = sourceCode.getLastToken(fixerTarget); - - return [...parensFixer, fixer.insertTextAfter(lastToken, output)]; - } - } - - const firstToken = sourceCode.getFirstToken( - node.parent.type === "VariableDeclarator" - ? node.parent.parent : node - ); - - const commentText = formatComments(comments); - - const commentBeforeExpression = fixer.insertTextBefore( - firstToken, - `${commentText}\n` - ); - - return [placeBesides, commentBeforeExpression]; - } - - return placeBesides; - } + fix: autoFixBesides(tokenBefore, fixerTarget, node) }); } } From 706a48eb75e61665881a43221b7eecea2c0799bb Mon Sep 17 00:00:00 2001 From: dios Date: Mon, 9 Jul 2018 15:52:04 -0700 Subject: [PATCH 13/24] REmove extra semicolon from top --- lib/rules/implicit-arrow-linebreak.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 5fe0dad04e1..48eb47d0150 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -8,7 +8,7 @@ const { isArrowToken, isParenthesised, isOpeningParenToken -} = require("../ast-utils");; +} = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition From 089310a662448cee49f0619df75ff65ecd9cc5df Mon Sep 17 00:00:00 2001 From: dios Date: Mon, 9 Jul 2018 18:29:05 -0700 Subject: [PATCH 14/24] Add test cases for async arrow functions, method chains, object literals, add parameter and documentation for column for formatComments, add findFirstToken helper --- lib/rules/implicit-arrow-linebreak.js | 26 ++++-- tests/lib/rules/implicit-arrow-linebreak.js | 90 ++++++++++++++++++++- 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 48eb47d0150..1141a984fd4 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -46,10 +46,16 @@ module.exports = { /** * Formats the comments depending on whether it's a line or block comment. * @param {Comment[]} comments The array of comments between the arrow and body + * @param {Integer} column The column number of the first token * @returns {string} A string of comment text joined by line breaks */ +<<<<<<< HEAD function formatComments(comments) { +======= + function formatComments(comments, column) { + const whiteSpaces = " ".repeat(column); +>>>>>>> 759d487d... Add test cases for async arrow functions, method chains, object literals, add parameter and documentation for column for formatComments, add findFirstToken helper return `${comments.map(comment => { @@ -64,7 +70,11 @@ module.exports = { /** * Finds the first token depending on the parent type * @param {Node} node The validated node +<<<<<<< HEAD * @returns {Token|Node} The node to prepend comments to +======= + * @returns {Token} The node to prepend comments to +>>>>>>> 759d487d... Add test cases for async arrow functions, method chains, object literals, add parameter and documentation for column for formatComments, add findFirstToken helper */ function findFirstToken(node) { switch (node.parent.type) { @@ -89,13 +99,11 @@ module.exports = { const parenthesesFixes = []; let closingParentheses = ""; - let followingBody; + let followingBody = fixerTarget; let currentArrow = arrow; while (currentArrow) { - followingBody = sourceCode.getTokenAfter(currentArrow, token => !isOpeningParenToken(token)); - if (!isParenthesised(sourceCode, followingBody)) { parenthesesFixes.push( fixer.insertTextAfter(currentArrow, " (") @@ -110,6 +118,10 @@ module.exports = { } currentArrow = sourceCode.getTokenAfter(currentArrow, isArrowToken); + + if (currentArrow) { + followingBody = sourceCode.getTokenAfter(currentArrow, token => !isOpeningParenToken(token)); + } } return [...parenthesesFixes, @@ -146,11 +158,13 @@ module.exports = { return null; } - const commentText = formatComments(comments); + const firstToken = findFirstToken(node); + + const commentText = formatComments(comments, firstToken.loc.start.column); const commentBeforeExpression = fixer.insertTextBeforeRange( - sourceCode.ast.tokens[0].range, - `${commentText}\n` + firstToken.range, + commentText ); return [placeBesides, commentBeforeExpression]; diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 454592962e4..d30a1c675f7 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -139,7 +139,8 @@ ruleTester.run("implicit-arrow-linebreak", rule, { bar `, output: ` - // test comment\n(foo) => bar + // test comment + (foo) => bar `, errors: [UNEXPECTED_LINEBREAK] }, { @@ -149,7 +150,8 @@ ruleTester.run("implicit-arrow-linebreak", rule, { [] `, output: ` - // comment\nconst foo = () => [] + // comment + const foo = () => [] `, errors: [UNEXPECTED_LINEBREAK] }, { @@ -220,7 +222,8 @@ ruleTester.run("implicit-arrow-linebreak", rule, { bar `, output: ` - /* test comment */\n(foo) => bar + /* test comment */ + (foo) => bar `, errors: [UNEXPECTED_LINEBREAK] }, { @@ -260,6 +263,87 @@ ruleTester.run("implicit-arrow-linebreak", rule, { ) `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + const foo = { + id: 'bar', + prop: (foo1) => + // comment + 'returning this string', + } + `, + output: ` + const foo = { + id: 'bar', + // comment + prop: (foo1) => 'returning this string', + } + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + [ foo => + // comment + 'bar' + ] + `, + output: ` + [ // comment + foo => 'bar' + ] + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + "foo".split('').map((char) => + // comment + char + ) + `, + output: ` + // comment + "foo".split('').map((char) => char + ) + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + async foo => + // comment + 'string' + `, + output: ` + // comment + async foo => 'string' + `, + parserOptions: { ecmaVersion: 8 }, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + async foo => + // comment + // another + bar; + `, + output: ` + // comment + // another + async foo => bar; + `, + parserOptions: { ecmaVersion: 8 }, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + async (foo) => + // comment + 'string' + `, + output: ` + // comment + async (foo) => 'string' + `, + parserOptions: { ecmaVersion: 8 }, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From d50c95fd3883f4a45388d25e5ea2f8efedd148cd Mon Sep 17 00:00:00 2001 From: Peanut Enthusiast Date: Tue, 10 Jul 2018 17:00:48 -0700 Subject: [PATCH 15/24] Fix lines for cherry-pick --- lib/rules/implicit-arrow-linebreak.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index 1141a984fd4..c5e62c6b2bf 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -49,13 +49,9 @@ module.exports = { * @param {Integer} column The column number of the first token * @returns {string} A string of comment text joined by line breaks */ -<<<<<<< HEAD - function formatComments(comments) { -======= function formatComments(comments, column) { const whiteSpaces = " ".repeat(column); ->>>>>>> 759d487d... Add test cases for async arrow functions, method chains, object literals, add parameter and documentation for column for formatComments, add findFirstToken helper return `${comments.map(comment => { @@ -70,11 +66,7 @@ module.exports = { /** * Finds the first token depending on the parent type * @param {Node} node The validated node -<<<<<<< HEAD * @returns {Token|Node} The node to prepend comments to -======= - * @returns {Token} The node to prepend comments to ->>>>>>> 759d487d... Add test cases for async arrow functions, method chains, object literals, add parameter and documentation for column for formatComments, add findFirstToken helper */ function findFirstToken(node) { switch (node.parent.type) { From 2daf6c9c4ef00386048a905cd872e8c2330b00d8 Mon Sep 17 00:00:00 2001 From: Peanut Enthusiast Date: Tue, 10 Jul 2018 17:04:36 -0700 Subject: [PATCH 16/24] Remove line --- lib/rules/implicit-arrow-linebreak.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index c5e62c6b2bf..cac8789356f 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -49,7 +49,6 @@ module.exports = { * @param {Integer} column The column number of the first token * @returns {string} A string of comment text joined by line breaks */ - function formatComments(comments, column) { const whiteSpaces = " ".repeat(column); From f52d5d56814322b5950eee59ece292c72f72a593 Mon Sep 17 00:00:00 2001 From: Peanut Enthusiast Date: Tue, 10 Jul 2018 17:23:34 -0700 Subject: [PATCH 17/24] Rename fixerTarget to arrowBody for autoFixBesides and addParentheses functions --- lib/rules/implicit-arrow-linebreak.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index cac8789356f..c66b96eb56e 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -83,15 +83,14 @@ module.exports = { * Helper function for adding parentheses fixes for nodes containing nested arrow functions * @param {Fixer} fixer Fixer * @param {Token} arrow - The arrow token - * @param {ASTNode} fixerTarget - The arrow function body + * @param {ASTNode} arrowBody - The arrow function body * @returns {Function[]} autofixer -- wraps function bodies with parentheses */ - function addParentheses(fixer, arrow, fixerTarget) { + function addParentheses(fixer, arrow, arrowBody) { const parenthesesFixes = []; let closingParentheses = ""; - let followingBody = fixerTarget; - + let followingBody = arrowBody; let currentArrow = arrow; while (currentArrow) { @@ -116,7 +115,7 @@ module.exports = { } return [...parenthesesFixes, - fixer.insertTextAfter(fixerTarget, closingParentheses) + fixer.insertTextAfter(arrowBody, closingParentheses) ]; } @@ -125,16 +124,16 @@ module.exports = { * If comments exist, prepends the comments before the arrow function. * If the function body contains arrow functions, appends the function bodies with parentheses. * @param {Token} arrow The arrow token. - * @param {ASTNode} fixerTarget the function body - * @param {ASTNode} node The node + * @param {ASTNode} arrowBody the function body + * @param {ASTNode} node The evaluated node * @returns {Function} autofixer -- validates the node to adhere to besides */ - function autoFixBesides(arrow, fixerTarget, node) { + function autoFixBesides(arrow, arrowBody, node) { return fixer => { - const placeBesides = fixer.replaceTextRange([arrow.range[1], fixerTarget.range[0]], " "); + const placeBesides = fixer.replaceTextRange([arrow.range[1], arrowBody.range[0]], " "); const comments = sourceCode.getCommentsInside(node).filter(comment => - comment.loc.start.line < fixerTarget.loc.start.line); + comment.loc.start.line < arrowBody.loc.start.line); if (comments.length) { @@ -142,7 +141,7 @@ module.exports = { // Check if any arrow functions follow if (sourceCode.getTokenAfter(arrow, isArrowToken)) { - return addParentheses(fixer, arrow, fixerTarget); + return addParentheses(fixer, arrow, arrowBody); } if (precedingArrow) { From 4ee9ac52a151e772f9a1f41f858752c1af32fffb Mon Sep 17 00:00:00 2001 From: dios Date: Wed, 22 Aug 2018 11:06:56 -0700 Subject: [PATCH 18/24] Add valid test cases --- tests/lib/rules/implicit-arrow-linebreak.js | 71 ++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index d30a1c675f7..118b669dc4e 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -37,9 +37,76 @@ ruleTester.run("implicit-arrow-linebreak", rule, { `(foo) => ( bar )`, + "(foo) => bar();", + ` + //comment + foo => bar; + `, + ` + foo => ( + // comment + bar => ( + // another comment + baz + ) + ) + `, + ` + foo => ( + // comment + bar => baz + ) + `, + ` + /* text */ + () => bar; + `, + ` + /* foo */ + const bar = () => baz; + `, + ` + (foo) => ( + //comment + bar + ) + `, + ` + [ // comment + foo => 'bar' + ] + `, + ` + /* + One two three four + Five six seven nine. + */ + (foo) => bar + `, + ` + const foo = { + id: 'bar', + // comment + prop: (foo1) => 'returning this string', + } + `, + ` + // comment + "foo".split('').map((char) => char + ) + `, { - code: "(foo) => bar();", - options: ["beside"] + code: ` + async foo => () => bar; + `, + parserOptions: { ecmaVersion: 8 }, + }, + { + code: ` + // comment + async foo => 'string' + `, + parserOptions: { ecmaVersion: 8 }, }, // 'below' option From 37bd7a023b458c1cb3fc72c0d7087739abf6c32c Mon Sep 17 00:00:00 2001 From: dios Date: Wed, 22 Aug 2018 11:34:51 -0700 Subject: [PATCH 19/24] Account for promise constructor and callback test cases --- tests/lib/rules/implicit-arrow-linebreak.js | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 118b669dc4e..9673043c800 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -411,6 +411,32 @@ ruleTester.run("implicit-arrow-linebreak", rule, { `, parserOptions: { ecmaVersion: 8 }, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + new Promise((resolve, reject) => + // comment + resolve() + ) + `, + output: ` + new Promise(// comment + (resolve, reject) => resolve() + ) + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + foo('', boo => + // comment + bar + ) + `, + output: ` + // comment + foo('', boo => bar + ) + `, + errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From 157fdec54cac772d7512b78b54e44a3eca183ad0 Mon Sep 17 00:00:00 2001 From: dios Date: Wed, 22 Aug 2018 15:53:11 -0700 Subject: [PATCH 20/24] Add test cases for multiline comments --- tests/lib/rules/implicit-arrow-linebreak.js | 125 ++++++++++++++++---- 1 file changed, 99 insertions(+), 26 deletions(-) diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 9673043c800..71825ce212e 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -373,6 +373,105 @@ ruleTester.run("implicit-arrow-linebreak", rule, { ) `, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + new Promise((resolve, reject) => + // comment + resolve() + ) + `, + output: ` + new Promise(// comment + (resolve, reject) => resolve() + ) + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + () => + /* + succinct + explanation + of code + */ + bar + `, + output: ` + /* + succinct + explanation + of code + */ + () => bar + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + stepOne => + /* + here is + what is + happening + */ + stepTwo => + // then this happens + stepThree`, + output: ` + stepOne => ( + /* + here is + what is + happening + */ + stepTwo => ( + // then this happens + stepThree + ) + )`, + errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] + }, { + code: ` + () => + /* + multi + line + */ + bar => + /* + many + lines + */ + baz + `, + output: ` + () => ( + /* + multi + line + */ + bar => ( + /* + many + lines + */ + baz + ) + ) + `, + errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] + }, { + code: ` + foo('', boo => + // comment + bar + ) + `, + output: ` + // comment + foo('', boo => bar + ) + `, + errors: [UNEXPECTED_LINEBREAK] }, { code: ` async foo => @@ -411,32 +510,6 @@ ruleTester.run("implicit-arrow-linebreak", rule, { `, parserOptions: { ecmaVersion: 8 }, errors: [UNEXPECTED_LINEBREAK] - }, { - code: ` - new Promise((resolve, reject) => - // comment - resolve() - ) - `, - output: ` - new Promise(// comment - (resolve, reject) => resolve() - ) - `, - errors: [UNEXPECTED_LINEBREAK] - }, { - code: ` - foo('', boo => - // comment - bar - ) - `, - output: ` - // comment - foo('', boo => bar - ) - `, - errors: [UNEXPECTED_LINEBREAK] }, // 'below' option From 94523311e96b19b5a19826883a39e01e0569813a Mon Sep 17 00:00:00 2001 From: dios Date: Wed, 22 Aug 2018 16:12:15 -0700 Subject: [PATCH 21/24] Remove dangling commas, add comments and extra details to jsdocs for clarity --- lib/rules/implicit-arrow-linebreak.js | 23 ++++++++++++--------- tests/lib/rules/implicit-arrow-linebreak.js | 4 ++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index c66b96eb56e..31c53e5c7a3 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -63,16 +63,20 @@ module.exports = { } /** - * Finds the first token depending on the parent type + * Finds the first token to prepend comments to depending on the parent type * @param {Node} node The validated node * @returns {Token|Node} The node to prepend comments to */ function findFirstToken(node) { switch (node.parent.type) { case "VariableDeclarator": + + // find the grandparent, i.e. const, let, var return sourceCode.getFirstToken(node.parent.parent); case "CallExpression": case "Property": + + // find the object key return sourceCode.getFirstToken(node.parent); default: return node; @@ -123,28 +127,27 @@ module.exports = { * Autofixes the function body to collapse onto the same line as the arrow. * If comments exist, prepends the comments before the arrow function. * If the function body contains arrow functions, appends the function bodies with parentheses. - * @param {Token} arrow The arrow token. + * @param {Token} arrowToken The arrow token. * @param {ASTNode} arrowBody the function body * @param {ASTNode} node The evaluated node * @returns {Function} autofixer -- validates the node to adhere to besides */ - function autoFixBesides(arrow, arrowBody, node) { + function autoFixBesides(arrowToken, arrowBody, node) { return fixer => { - const placeBesides = fixer.replaceTextRange([arrow.range[1], arrowBody.range[0]], " "); + const placeBesides = fixer.replaceTextRange([arrowToken.range[1], arrowBody.range[0]], " "); const comments = sourceCode.getCommentsInside(node).filter(comment => comment.loc.start.line < arrowBody.loc.start.line); if (comments.length) { - const precedingArrow = sourceCode.getTokenBefore(arrow, isArrowToken); - - // Check if any arrow functions follow - if (sourceCode.getTokenAfter(arrow, isArrowToken)) { - return addParentheses(fixer, arrow, arrowBody); + // If any arrow functions follow, return the necessary parens fixes. + if (sourceCode.getTokenAfter(arrowToken, isArrowToken)) { + return addParentheses(fixer, arrowToken, arrowBody); } - if (precedingArrow) { + // If any arrow functions precede, the necessary fixes have already been returned, so return null. + if (sourceCode.getTokenBefore(arrowToken, isArrowToken)) { return null; } diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 71825ce212e..9eb3c0559ff 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -99,14 +99,14 @@ ruleTester.run("implicit-arrow-linebreak", rule, { code: ` async foo => () => bar; `, - parserOptions: { ecmaVersion: 8 }, + parserOptions: { ecmaVersion: 8 } }, { code: ` // comment async foo => 'string' `, - parserOptions: { ecmaVersion: 8 }, + parserOptions: { ecmaVersion: 8 } }, // 'below' option From 6a2039a280f60fc2cc51b594b42c917ba8a760bf Mon Sep 17 00:00:00 2001 From: Peanut Enthusiast Date: Mon, 27 Aug 2018 10:16:58 -0700 Subject: [PATCH 22/24] Update branch, fix import statement for ast-utils --- lib/rules/implicit-arrow-linebreak.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index c66b96eb56e..b517a7fbaf8 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -8,7 +8,7 @@ const { isArrowToken, isParenthesised, isOpeningParenToken -} = require("../ast-utils"); +} = require("../util/ast-utils"); //------------------------------------------------------------------------------ // Rule Definition From 388db163e102bc962c90d1242e3d225e18adb1e0 Mon Sep 17 00:00:00 2001 From: dios Date: Thu, 6 Dec 2018 13:45:44 -0800 Subject: [PATCH 23/24] Apply requested change to string template for tests on lines 258 and 269 --- tests/lib/rules/implicit-arrow-linebreak.js | 37 ++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 9eb3c0559ff..6ed351ef964 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -255,23 +255,30 @@ ruleTester.run("implicit-arrow-linebreak", rule, { errors: [UNEXPECTED_LINEBREAK] }, { - code: `(foo) => - // comment - // another comment - bar`, - output: "// comment\n// another comment\n(foo) => bar", + code: ` + (foo) => + // comment + // another comment + bar`, + output: ` + // comment + // another comment + (foo) => bar`, errors: [UNEXPECTED_LINEBREAK] }, { - code: `(foo) => - // comment - ( - // another comment - bar - )`, - output: `// comment\n(foo) => ( - // another comment - bar - )`, + code: ` + (foo) => + // comment + ( + // another comment + bar + )`, + output: ` + // comment + (foo) => ( + // another comment + bar + )`, errors: [UNEXPECTED_LINEBREAK] }, { From 65a7b6114e9572d97a194e4abf4324301e83cec4 Mon Sep 17 00:00:00 2001 From: dios Date: Tue, 18 Dec 2018 13:33:36 -0800 Subject: [PATCH 24/24] Add and pass test cases for variable declarations with multiple declarations --- lib/rules/implicit-arrow-linebreak.js | 32 +++++++++----- tests/lib/rules/implicit-arrow-linebreak.js | 47 +++++++++++++++++++++ 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js index d19ef102576..fb7d603a35a 100644 --- a/lib/rules/implicit-arrow-linebreak.js +++ b/lib/rules/implicit-arrow-linebreak.js @@ -75,8 +75,12 @@ module.exports = { switch (node.parent.type) { case "VariableDeclarator": - // find the grandparent, i.e. const, let, var - return sourceCode.getFirstToken(node.parent.parent); + // If the parent is first or only declarator, return the declaration, else, declarator + return sourceCode.getFirstToken( + node.parent.parent.declarations.length === 1 || + node.parent.parent.declarations[0].id.name === node.parent.id.name + ? node.parent.parent : node.parent + ); case "CallExpression": case "Property": @@ -145,14 +149,22 @@ module.exports = { if (comments.length) { - // If any arrow functions follow, return the necessary parens fixes. - if (sourceCode.getTokenAfter(arrowToken, isArrowToken)) { - return addParentheses(fixer, arrowToken, arrowBody); - } - - // If any arrow functions precede, the necessary fixes have already been returned, so return null. - if (sourceCode.getTokenBefore(arrowToken, isArrowToken)) { - return null; + // If the grandparent is not a variable declarator + if ( + arrowBody.parent && + arrowBody.parent.parent && + arrowBody.parent.parent.type !== "VariableDeclarator" + ) { + + // If any arrow functions follow, return the necessary parens fixes. + if (sourceCode.getTokenAfter(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") { + return addParentheses(fixer, arrowToken, arrowBody); + } + + // If any arrow functions precede, the necessary fixes have already been returned, so return null. + if (sourceCode.getTokenBefore(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") { + return null; + } } const firstToken = findFirstToken(node); diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js index 6ed351ef964..f07182c1b5c 100644 --- a/tests/lib/rules/implicit-arrow-linebreak.js +++ b/tests/lib/rules/implicit-arrow-linebreak.js @@ -517,6 +517,53 @@ ruleTester.run("implicit-arrow-linebreak", rule, { `, parserOptions: { ecmaVersion: 8 }, errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + const foo = 1, + bar = 2, + baz = () => // comment + qux + `, + output: ` + const foo = 1, + bar = 2, + // comment + baz = () => qux + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + const foo = () => + //comment + qux, + bar = 2, + baz = 3 + `, + output: ` + //comment + const foo = () => qux, + bar = 2, + baz = 3 + `, + errors: [UNEXPECTED_LINEBREAK] + }, { + code: ` + const foo = () => + //two + 1, + boo = () => + //comment + 2, + bop = "what" + `, + output: ` + //two + const foo = () => 1, + //comment + boo = () => 2, + bop = "what" + `, + errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] }, // 'below' option