Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

newline-after-var.js 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /**
  2. * @fileoverview Rule to check empty newline after "var" statement
  3. * @author Gopal Venkatesan
  4. * @deprecated
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Requirements
  9. //------------------------------------------------------------------------------
  10. const astUtils = require("../util/ast-utils");
  11. //------------------------------------------------------------------------------
  12. // Rule Definition
  13. //------------------------------------------------------------------------------
  14. module.exports = {
  15. meta: {
  16. type: "layout",
  17. docs: {
  18. description: "require or disallow an empty line after variable declarations",
  19. category: "Stylistic Issues",
  20. recommended: false,
  21. url: "https://eslint.org/docs/rules/newline-after-var"
  22. },
  23. schema: [
  24. {
  25. enum: ["never", "always"]
  26. }
  27. ],
  28. fixable: "whitespace",
  29. deprecated: true,
  30. replacedBy: ["padding-line-between-statements"]
  31. },
  32. create(context) {
  33. const ALWAYS_MESSAGE = "Expected blank line after variable declarations.",
  34. NEVER_MESSAGE = "Unexpected blank line after variable declarations.";
  35. const sourceCode = context.getSourceCode();
  36. // Default `mode` to "always".
  37. const mode = context.options[0] === "never" ? "never" : "always";
  38. // Cache starting and ending line numbers of comments for faster lookup
  39. const commentEndLine = sourceCode.getAllComments().reduce((result, token) => {
  40. result[token.loc.start.line] = token.loc.end.line;
  41. return result;
  42. }, {});
  43. //--------------------------------------------------------------------------
  44. // Helpers
  45. //--------------------------------------------------------------------------
  46. /**
  47. * Gets a token from the given node to compare line to the next statement.
  48. *
  49. * In general, the token is the last token of the node. However, the token is the second last token if the following conditions satisfy.
  50. *
  51. * - The last token is semicolon.
  52. * - The semicolon is on a different line from the previous token of the semicolon.
  53. *
  54. * This behavior would address semicolon-less style code. e.g.:
  55. *
  56. * var foo = 1
  57. *
  58. * ;(a || b).doSomething()
  59. *
  60. * @param {ASTNode} node - The node to get.
  61. * @returns {Token} The token to compare line to the next statement.
  62. */
  63. function getLastToken(node) {
  64. const lastToken = sourceCode.getLastToken(node);
  65. if (lastToken.type === "Punctuator" && lastToken.value === ";") {
  66. const prevToken = sourceCode.getTokenBefore(lastToken);
  67. if (prevToken.loc.end.line !== lastToken.loc.start.line) {
  68. return prevToken;
  69. }
  70. }
  71. return lastToken;
  72. }
  73. /**
  74. * Determine if provided keyword is a variable declaration
  75. * @private
  76. * @param {string} keyword - keyword to test
  77. * @returns {boolean} True if `keyword` is a type of var
  78. */
  79. function isVar(keyword) {
  80. return keyword === "var" || keyword === "let" || keyword === "const";
  81. }
  82. /**
  83. * Determine if provided keyword is a variant of for specifiers
  84. * @private
  85. * @param {string} keyword - keyword to test
  86. * @returns {boolean} True if `keyword` is a variant of for specifier
  87. */
  88. function isForTypeSpecifier(keyword) {
  89. return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement";
  90. }
  91. /**
  92. * Determine if provided keyword is an export specifiers
  93. * @private
  94. * @param {string} nodeType - nodeType to test
  95. * @returns {boolean} True if `nodeType` is an export specifier
  96. */
  97. function isExportSpecifier(nodeType) {
  98. return nodeType === "ExportNamedDeclaration" || nodeType === "ExportSpecifier" ||
  99. nodeType === "ExportDefaultDeclaration" || nodeType === "ExportAllDeclaration";
  100. }
  101. /**
  102. * Determine if provided node is the last of their parent block.
  103. * @private
  104. * @param {ASTNode} node - node to test
  105. * @returns {boolean} True if `node` is last of their parent block.
  106. */
  107. function isLastNode(node) {
  108. const token = sourceCode.getTokenAfter(node);
  109. return !token || (token.type === "Punctuator" && token.value === "}");
  110. }
  111. /**
  112. * Gets the last line of a group of consecutive comments
  113. * @param {number} commentStartLine The starting line of the group
  114. * @returns {number} The number of the last comment line of the group
  115. */
  116. function getLastCommentLineOfBlock(commentStartLine) {
  117. const currentCommentEnd = commentEndLine[commentStartLine];
  118. return commentEndLine[currentCommentEnd + 1] ? getLastCommentLineOfBlock(currentCommentEnd + 1) : currentCommentEnd;
  119. }
  120. /**
  121. * Determine if a token starts more than one line after a comment ends
  122. * @param {token} token The token being checked
  123. * @param {integer} commentStartLine The line number on which the comment starts
  124. * @returns {boolean} True if `token` does not start immediately after a comment
  125. */
  126. function hasBlankLineAfterComment(token, commentStartLine) {
  127. return token.loc.start.line > getLastCommentLineOfBlock(commentStartLine) + 1;
  128. }
  129. /**
  130. * Checks that a blank line exists after a variable declaration when mode is
  131. * set to "always", or checks that there is no blank line when mode is set
  132. * to "never"
  133. * @private
  134. * @param {ASTNode} node - `VariableDeclaration` node to test
  135. * @returns {void}
  136. */
  137. function checkForBlankLine(node) {
  138. /*
  139. * lastToken is the last token on the node's line. It will usually also be the last token of the node, but it will
  140. * sometimes be second-last if there is a semicolon on a different line.
  141. */
  142. const lastToken = getLastToken(node),
  143. /*
  144. * If lastToken is the last token of the node, nextToken should be the token after the node. Otherwise, nextToken
  145. * is the last token of the node.
  146. */
  147. nextToken = lastToken === sourceCode.getLastToken(node) ? sourceCode.getTokenAfter(node) : sourceCode.getLastToken(node),
  148. nextLineNum = lastToken.loc.end.line + 1;
  149. // Ignore if there is no following statement
  150. if (!nextToken) {
  151. return;
  152. }
  153. // Ignore if parent of node is a for variant
  154. if (isForTypeSpecifier(node.parent.type)) {
  155. return;
  156. }
  157. // Ignore if parent of node is an export specifier
  158. if (isExportSpecifier(node.parent.type)) {
  159. return;
  160. }
  161. /*
  162. * Some coding styles use multiple `var` statements, so do nothing if
  163. * the next token is a `var` statement.
  164. */
  165. if (nextToken.type === "Keyword" && isVar(nextToken.value)) {
  166. return;
  167. }
  168. // Ignore if it is last statement in a block
  169. if (isLastNode(node)) {
  170. return;
  171. }
  172. // Next statement is not a `var`...
  173. const noNextLineToken = nextToken.loc.start.line > nextLineNum;
  174. const hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined");
  175. if (mode === "never" && noNextLineToken && !hasNextLineComment) {
  176. context.report({
  177. node,
  178. message: NEVER_MESSAGE,
  179. data: { identifier: node.name },
  180. fix(fixer) {
  181. const linesBetween = sourceCode.getText().slice(lastToken.range[1], nextToken.range[0]).split(astUtils.LINEBREAK_MATCHER);
  182. return fixer.replaceTextRange([lastToken.range[1], nextToken.range[0]], `${linesBetween.slice(0, -1).join("")}\n${linesBetween[linesBetween.length - 1]}`);
  183. }
  184. });
  185. }
  186. // Token on the next line, or comment without blank line
  187. if (
  188. mode === "always" && (
  189. !noNextLineToken ||
  190. hasNextLineComment && !hasBlankLineAfterComment(nextToken, nextLineNum)
  191. )
  192. ) {
  193. context.report({
  194. node,
  195. message: ALWAYS_MESSAGE,
  196. data: { identifier: node.name },
  197. fix(fixer) {
  198. if ((noNextLineToken ? getLastCommentLineOfBlock(nextLineNum) : lastToken.loc.end.line) === nextToken.loc.start.line) {
  199. return fixer.insertTextBefore(nextToken, "\n\n");
  200. }
  201. return fixer.insertTextBeforeRange([nextToken.range[0] - nextToken.loc.start.column, nextToken.range[1]], "\n");
  202. }
  203. });
  204. }
  205. }
  206. //--------------------------------------------------------------------------
  207. // Public
  208. //--------------------------------------------------------------------------
  209. return {
  210. VariableDeclaration: checkForBlankLine
  211. };
  212. }
  213. };