summaryrefslogtreecommitdiff
path: root/tools/eslint/lib/rules/newline-after-var.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/eslint/lib/rules/newline-after-var.js')
-rw-r--r--tools/eslint/lib/rules/newline-after-var.js61
1 files changed, 55 insertions, 6 deletions
diff --git a/tools/eslint/lib/rules/newline-after-var.js b/tools/eslint/lib/rules/newline-after-var.js
index e1ade14bde..9e7d859931 100644
--- a/tools/eslint/lib/rules/newline-after-var.js
+++ b/tools/eslint/lib/rules/newline-after-var.js
@@ -3,6 +3,7 @@
* @author Gopal Venkatesan
* @copyright 2015 Gopal Venkatesan. All rights reserved.
* @copyright 2015 Casey Visco. All rights reserved.
+ * @copyright 2015 Ian VanSchooten. All rights reserved.
*/
"use strict";
@@ -20,10 +21,11 @@ module.exports = function(context) {
// be treated as "always" and the only special case is "never"
var mode = context.options[0] === "never" ? "never" : "always";
- // Cache line numbers of comments for faster lookup
- var comments = context.getAllComments().map(function (token) {
- return token.loc.start.line;
- });
+ // Cache starting and ending line numbers of comments for faster lookup
+ var commentEndLine = context.getAllComments().reduce(function(result, token) {
+ result[token.loc.start.line] = token.loc.end.line;
+ return result;
+ }, {});
//--------------------------------------------------------------------------
@@ -62,6 +64,42 @@ module.exports = function(context) {
}
/**
+ * Determine if provided nodeType is a function specifier
+ * @private
+ * @param {string} nodeType - nodeType to test
+ * @returns {boolean} True if `nodeType` is a function specifier
+ */
+ function isFunctionSpecifier(nodeType) {
+ return nodeType === "FunctionDeclaration" || nodeType === "FunctionExpression" ||
+ nodeType === "ArrowFunctionExpression";
+ }
+
+ /**
+ * Determine if provided node is the last of his parent
+ * @private
+ * @param {ASTNode} node - node to test
+ * @returns {boolean} True if `node` is last of his parent
+ */
+ function isLastNode(node) {
+ return node.parent.body[node.parent.body.length - 1] === node;
+ }
+
+ /**
+ * Determine if a token starts more than one line after a comment ends
+ * @param {token} token The token being checked
+ * @param {integer} commentStartLine The line number on which the comment starts
+ * @returns {boolean} True if `token` does not start immediately after a comment
+ */
+ function hasBlankLineAfterComment(token, commentStartLine) {
+ var commentEnd = commentEndLine[commentStartLine];
+ // If there's another comment, repeat check for blank line
+ if (commentEndLine[commentEnd + 1]) {
+ return hasBlankLineAfterComment(token, commentEnd + 1);
+ }
+ return (token.loc.start.line > commentEndLine[commentStartLine] + 1);
+ }
+
+ /**
* Checks that a blank line exists after a variable declaration when mode is
* set to "always", or checks that there is no blank line when mode is set
* to "never"
@@ -97,15 +135,26 @@ module.exports = function(context) {
return;
}
+ // Ignore if it is last statement in a function
+ if (node.parent.parent && isFunctionSpecifier(node.parent.parent.type) && isLastNode(node)) {
+ return;
+ }
+
// Next statement is not a `var`...
noNextLineToken = nextToken.loc.start.line > nextLineNum;
- hasNextLineComment = comments.indexOf(nextLineNum) >= 0;
+ hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined");
if (mode === "never" && noNextLineToken && !hasNextLineComment) {
context.report(node, NEVER_MESSAGE, { identifier: node.name });
}
- if (mode === "always" && (!noNextLineToken || hasNextLineComment)) {
+ // Token on the next line, or comment without blank line
+ if (
+ mode === "always" && (
+ !noNextLineToken ||
+ hasNextLineComment && !hasBlankLineAfterComment(nextToken, nextLineNum)
+ )
+ ) {
context.report(node, ALWAYS_MESSAGE, { identifier: node.name });
}
}