Skip to content

Commit

Permalink
Update: add fixer for newline-before-return (fixes eslint#5958)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitorbal committed Sep 3, 2016
1 parent 326f457 commit 52b6ab0
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 36 deletions.
70 changes: 55 additions & 15 deletions lib/rules/newline-before-return.js
Expand Up @@ -16,6 +16,8 @@ module.exports = {
recommended: false
},

fixable: "whitespace",

schema: []
},

Expand Down Expand Up @@ -103,35 +105,67 @@ module.exports = {
}

/**
* Checks whether node is preceded by a newline
* @param {ASTNode} node - node to check
* @returns {boolean} Whether or not the node is preceded by a newline
* @private
* Returns the line number of the token before the node that is passed in as an argument
* @param {ASTNode} node - node from
* @returns {number} Line number of the token before `node`
*/
function hasNewlineBefore(node) {
const tokenBefore = sourceCode.getTokenBefore(node),
lineNumNode = node.loc.start.line;
function getLineNumberOfTokenBefore(node) {
const tokenBefore = sourceCode.getTokenBefore(node);
let lineNumTokenBefore;

/**
* Global return (at the beginning of a script) is a special case.
* If there is no token before `return`, then we expect no line
* break before the return. Comments are allowed to occupy lines
* before the global return, just no blank lines.
* Setting lineNumTokenBefore to zero in that case results in the
* desired behavior.
*/
* Global return (at the beginning of a script) is a special case.
* If there is no token before `return`, then we expect no line
* break before the return. Comments are allowed to occupy lines
* before the global return, just no blank lines.
* Setting lineNumTokenBefore to zero in that case results in the
* desired behavior.
*/
if (tokenBefore) {
lineNumTokenBefore = tokenBefore.loc.end.line;
} else {
lineNumTokenBefore = 0; // global return at beginning of script
}

return lineNumTokenBefore;
}

/**
* Checks whether node is preceded by a newline
* @param {ASTNode} node - node to check
* @returns {boolean} Whether or not the node is preceded by a newline
* @private
*/
function hasNewlineBefore(node) {
const lineNumNode = node.loc.start.line;
const lineNumTokenBefore = getLineNumberOfTokenBefore(node);

const commentLines = calcCommentLines(node, lineNumTokenBefore);

return (lineNumNode - lineNumTokenBefore - commentLines) > 1;
}

/**
* Checks whether it is safe to apply a fix to a given return statement.
*
* The fix is not considered safe if the given return statement has leading comments,
* as we cannot safely determine if the newline should be added before or after the comments.
* For more information, see: https://github.com/eslint/eslint/issues/5958#issuecomment-222767211
*
* @param {ASTNode} node - The return statement node to check.
* @returns {boolean} `true` if it can fix the node.
*/
function canFix(node) {
const lineNumTokenBefore = getLineNumberOfTokenBefore(node);
const tokenHasComments = calcCommentLines(node, lineNumTokenBefore) > 0;

if (tokenHasComments) {
return false;
}

return true;
}

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
Expand All @@ -141,7 +175,13 @@ module.exports = {
if (!isFirstNode(node) && !hasNewlineBefore(node)) {
context.report({
node,
message: "Expected newline before return statement."
message: "Expected newline before return statement.",
fix(fixer) {
if (canFix(node)) {
return fixer.insertTextBefore(node, "\n");
}
return null;
}
});
}
}
Expand Down
55 changes: 34 additions & 21 deletions tests/lib/rules/newline-before-return.js
Expand Up @@ -112,77 +112,90 @@ ruleTester.run("newline-before-return", rule, {
invalid: [
{
code: "function a() {\nvar b;\nreturn;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nvar b;\n\nreturn;\n}"
},
{
code: "function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\nreturn d;\n}\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\nreturn d;\n}\n}"
},
{
code: "function a() {\n while (b) {\nc();\nreturn;\n}\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\n while (b) {\nc();\n\nreturn;\n}\n}"
},
{
code: "function a() {\ndo {\nc();\nreturn;\n} while (b);\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\ndo {\nc();\n\nreturn;\n} while (b);\n}"
},
{
code: "function a() {\nfor (var b; b < c; b++) {\nc();\nreturn;\n}\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nfor (var b; b < c; b++) {\nc();\n\nreturn;\n}\n}"
},
{
code: "function a() {\nfor (b in c) {\nd();\nreturn;\n}\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nfor (b in c) {\nd();\n\nreturn;\n}\n}"
},
{
code: "function a() {\nfor (b of c) {\nd();\nreturn;\n}\n}",
parserOptions: { ecmaVersion: 6 },
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nfor (b of c) {\nd();\n\nreturn;\n}\n}"
},
{
code: "function a() {\nif (b) {\nc();\n}\n//comment\nreturn b;\n}",
errors: ["Expected newline before return statement."]
},
{
code: "function a() {\nif (b) {\nc();\n}\n//comment\nreturn b;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) {\nc();\n}\n//comment\nreturn b;\n}"
},
{
code: "function a() {\n/*comment\ncomment*/\nif (b) {\nc();\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n/*multi-line\ncomment*/\nreturn e;\n}",
errors: ["Expected newline before return statement.", "Expected newline before return statement."]
errors: ["Expected newline before return statement.", "Expected newline before return statement."],
output: "function a() {\n/*comment\ncomment*/\nif (b) {\nc();\n\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n/*multi-line\ncomment*/\nreturn e;\n}"
},
{
code: "function a() {\nif (b) { return; } //comment\nreturn c;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) { return; } //comment\n\nreturn c;\n}"
},
{
code: "function a() {\nif (b) { return; } /*multi-line\ncomment*/\nreturn c;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) { return; } /*multi-line\ncomment*/\nreturn c;\n}"
},
{
code: "function a() {\nif (b) { return; }\n/*multi-line\ncomment*/ return c;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) { return; }\n/*multi-line\ncomment*/ return c;\n}"
},
{
code: "function a() {\nif (b) { return; } /*multi-line\ncomment*/ return c;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nif (b) { return; } /*multi-line\ncomment*/ \nreturn c;\n}"
},
{
code: "var a;\nreturn;",
parserOptions: { ecmaFeatures: { globalReturn: true } },
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "var a;\n\nreturn;"
},
{
code: "function a() {\n{\n//comment\n}\nreturn\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\n{\n//comment\n}\n\nreturn\n}"
},
{
code: "function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\nreturn c;\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\n\nreturn c;\n}"
},
{
code: "function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\nreturn;\n}\n}",
errors: ["Expected newline before return statement."]
errors: ["Expected newline before return statement."],
output: "function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\n\nreturn;\n}\n}"
}
]
});

0 comments on commit 52b6ab0

Please sign in to comment.