项目原始demo,不改动
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
Dieses Repo ist archiviert. Du kannst Dateien sehen und es klonen, kannst aber nicht pushen oder Issues/Pull-Requests öffnen.

newline-after-var.js 9.6 KiB

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