项目原始demo,不改动
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 

200 lines
6.6 KiB

  1. /**
  2. * @fileoverview Rule to check the spacing around the * in generator functions.
  3. * @author Jamund Ferguson
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. const OVERRIDE_SCHEMA = {
  10. oneOf: [
  11. {
  12. enum: ["before", "after", "both", "neither"]
  13. },
  14. {
  15. type: "object",
  16. properties: {
  17. before: { type: "boolean" },
  18. after: { type: "boolean" }
  19. },
  20. additionalProperties: false
  21. }
  22. ]
  23. };
  24. module.exports = {
  25. meta: {
  26. docs: {
  27. description: "enforce consistent spacing around `*` operators in generator functions",
  28. category: "ECMAScript 6",
  29. recommended: false,
  30. url: "https://eslint.org/docs/rules/generator-star-spacing"
  31. },
  32. fixable: "whitespace",
  33. schema: [
  34. {
  35. oneOf: [
  36. {
  37. enum: ["before", "after", "both", "neither"]
  38. },
  39. {
  40. type: "object",
  41. properties: {
  42. before: { type: "boolean" },
  43. after: { type: "boolean" },
  44. named: OVERRIDE_SCHEMA,
  45. anonymous: OVERRIDE_SCHEMA,
  46. method: OVERRIDE_SCHEMA
  47. },
  48. additionalProperties: false
  49. }
  50. ]
  51. }
  52. ]
  53. },
  54. create(context) {
  55. const optionDefinitions = {
  56. before: { before: true, after: false },
  57. after: { before: false, after: true },
  58. both: { before: true, after: true },
  59. neither: { before: false, after: false }
  60. };
  61. /**
  62. * Returns resolved option definitions based on an option and defaults
  63. *
  64. * @param {any} option - The option object or string value
  65. * @param {Object} defaults - The defaults to use if options are not present
  66. * @returns {Object} the resolved object definition
  67. */
  68. function optionToDefinition(option, defaults) {
  69. if (!option) {
  70. return defaults;
  71. }
  72. return typeof option === "string"
  73. ? optionDefinitions[option]
  74. : Object.assign({}, defaults, option);
  75. }
  76. const modes = (function(option) {
  77. const defaults = optionToDefinition(option, optionDefinitions.before);
  78. return {
  79. named: optionToDefinition(option.named, defaults),
  80. anonymous: optionToDefinition(option.anonymous, defaults),
  81. method: optionToDefinition(option.method, defaults)
  82. };
  83. }(context.options[0] || {}));
  84. const sourceCode = context.getSourceCode();
  85. /**
  86. * Checks if the given token is a star token or not.
  87. *
  88. * @param {Token} token - The token to check.
  89. * @returns {boolean} `true` if the token is a star token.
  90. */
  91. function isStarToken(token) {
  92. return token.value === "*" && token.type === "Punctuator";
  93. }
  94. /**
  95. * Gets the generator star token of the given function node.
  96. *
  97. * @param {ASTNode} node - The function node to get.
  98. * @returns {Token} Found star token.
  99. */
  100. function getStarToken(node) {
  101. return sourceCode.getFirstToken(
  102. (node.parent.method || node.parent.type === "MethodDefinition") ? node.parent : node,
  103. isStarToken
  104. );
  105. }
  106. /**
  107. * Checks the spacing between two tokens before or after the star token.
  108. *
  109. * @param {string} kind Either "named", "anonymous", or "method"
  110. * @param {string} side Either "before" or "after".
  111. * @param {Token} leftToken `function` keyword token if side is "before", or
  112. * star token if side is "after".
  113. * @param {Token} rightToken Star token if side is "before", or identifier
  114. * token if side is "after".
  115. * @returns {void}
  116. */
  117. function checkSpacing(kind, side, leftToken, rightToken) {
  118. if (!!(rightToken.range[0] - leftToken.range[1]) !== modes[kind][side]) {
  119. const after = leftToken.value === "*";
  120. const spaceRequired = modes[kind][side];
  121. const node = after ? leftToken : rightToken;
  122. const type = spaceRequired ? "Missing" : "Unexpected";
  123. const message = "{{type}} space {{side}} *.";
  124. const data = {
  125. type,
  126. side
  127. };
  128. context.report({
  129. node,
  130. message,
  131. data,
  132. fix(fixer) {
  133. if (spaceRequired) {
  134. if (after) {
  135. return fixer.insertTextAfter(node, " ");
  136. }
  137. return fixer.insertTextBefore(node, " ");
  138. }
  139. return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
  140. }
  141. });
  142. }
  143. }
  144. /**
  145. * Enforces the spacing around the star if node is a generator function.
  146. *
  147. * @param {ASTNode} node A function expression or declaration node.
  148. * @returns {void}
  149. */
  150. function checkFunction(node) {
  151. if (!node.generator) {
  152. return;
  153. }
  154. const starToken = getStarToken(node);
  155. const prevToken = sourceCode.getTokenBefore(starToken);
  156. const nextToken = sourceCode.getTokenAfter(starToken);
  157. let kind = "named";
  158. if (node.parent.type === "MethodDefinition" || (node.parent.type === "Property" && node.parent.method)) {
  159. kind = "method";
  160. } else if (!node.id) {
  161. kind = "anonymous";
  162. }
  163. // Only check before when preceded by `function`|`static` keyword
  164. if (!(kind === "method" && starToken === sourceCode.getFirstToken(node.parent))) {
  165. checkSpacing(kind, "before", prevToken, starToken);
  166. }
  167. checkSpacing(kind, "after", starToken, nextToken);
  168. }
  169. return {
  170. FunctionDeclaration: checkFunction,
  171. FunctionExpression: checkFunction
  172. };
  173. }
  174. };