arrow-spacing.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * @fileoverview Rule to define spacing before/after arrow function's arrow.
  3. * @author Jxck
  4. * @deprecated in ESLint v8.53.0
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Requirements
  9. //------------------------------------------------------------------------------
  10. const astUtils = require("./utils/ast-utils");
  11. //------------------------------------------------------------------------------
  12. // Rule Definition
  13. //------------------------------------------------------------------------------
  14. /** @type {import('../types').Rule.RuleModule} */
  15. module.exports = {
  16. meta: {
  17. deprecated: {
  18. message: "Formatting rules are being moved out of ESLint core.",
  19. url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
  20. deprecatedSince: "8.53.0",
  21. availableUntil: "11.0.0",
  22. replacedBy: [
  23. {
  24. message:
  25. "ESLint Stylistic now maintains deprecated stylistic core rules.",
  26. url: "https://eslint.style/guide/migration",
  27. plugin: {
  28. name: "@stylistic/eslint-plugin",
  29. url: "https://eslint.style",
  30. },
  31. rule: {
  32. name: "arrow-spacing",
  33. url: "https://eslint.style/rules/arrow-spacing",
  34. },
  35. },
  36. ],
  37. },
  38. type: "layout",
  39. docs: {
  40. description:
  41. "Enforce consistent spacing before and after the arrow in arrow functions",
  42. recommended: false,
  43. url: "https://eslint.org/docs/latest/rules/arrow-spacing",
  44. },
  45. fixable: "whitespace",
  46. schema: [
  47. {
  48. type: "object",
  49. properties: {
  50. before: {
  51. type: "boolean",
  52. default: true,
  53. },
  54. after: {
  55. type: "boolean",
  56. default: true,
  57. },
  58. },
  59. additionalProperties: false,
  60. },
  61. ],
  62. messages: {
  63. expectedBefore: "Missing space before =>.",
  64. unexpectedBefore: "Unexpected space before =>.",
  65. expectedAfter: "Missing space after =>.",
  66. unexpectedAfter: "Unexpected space after =>.",
  67. },
  68. },
  69. create(context) {
  70. // merge rules with default
  71. const rule = Object.assign({}, context.options[0]);
  72. rule.before = rule.before !== false;
  73. rule.after = rule.after !== false;
  74. const sourceCode = context.sourceCode;
  75. /**
  76. * Get tokens of arrow(`=>`) and before/after arrow.
  77. * @param {ASTNode} node The arrow function node.
  78. * @returns {Object} Tokens of arrow and before/after arrow.
  79. */
  80. function getTokens(node) {
  81. const arrow = sourceCode.getTokenBefore(
  82. node.body,
  83. astUtils.isArrowToken,
  84. );
  85. return {
  86. before: sourceCode.getTokenBefore(arrow),
  87. arrow,
  88. after: sourceCode.getTokenAfter(arrow),
  89. };
  90. }
  91. /**
  92. * Count spaces before/after arrow(`=>`) token.
  93. * @param {Object} tokens Tokens before/after arrow.
  94. * @returns {Object} count of space before/after arrow.
  95. */
  96. function countSpaces(tokens) {
  97. const before = tokens.arrow.range[0] - tokens.before.range[1];
  98. const after = tokens.after.range[0] - tokens.arrow.range[1];
  99. return { before, after };
  100. }
  101. /**
  102. * Determines whether space(s) before after arrow(`=>`) is satisfy rule.
  103. * if before/after value is `true`, there should be space(s).
  104. * if before/after value is `false`, there should be no space.
  105. * @param {ASTNode} node The arrow function node.
  106. * @returns {void}
  107. */
  108. function spaces(node) {
  109. const tokens = getTokens(node);
  110. const countSpace = countSpaces(tokens);
  111. if (rule.before) {
  112. // should be space(s) before arrow
  113. if (countSpace.before === 0) {
  114. context.report({
  115. node: tokens.before,
  116. messageId: "expectedBefore",
  117. fix(fixer) {
  118. return fixer.insertTextBefore(tokens.arrow, " ");
  119. },
  120. });
  121. }
  122. } else {
  123. // should be no space before arrow
  124. if (countSpace.before > 0) {
  125. context.report({
  126. node: tokens.before,
  127. messageId: "unexpectedBefore",
  128. fix(fixer) {
  129. return fixer.removeRange([
  130. tokens.before.range[1],
  131. tokens.arrow.range[0],
  132. ]);
  133. },
  134. });
  135. }
  136. }
  137. if (rule.after) {
  138. // should be space(s) after arrow
  139. if (countSpace.after === 0) {
  140. context.report({
  141. node: tokens.after,
  142. messageId: "expectedAfter",
  143. fix(fixer) {
  144. return fixer.insertTextAfter(tokens.arrow, " ");
  145. },
  146. });
  147. }
  148. } else {
  149. // should be no space after arrow
  150. if (countSpace.after > 0) {
  151. context.report({
  152. node: tokens.after,
  153. messageId: "unexpectedAfter",
  154. fix(fixer) {
  155. return fixer.removeRange([
  156. tokens.arrow.range[1],
  157. tokens.after.range[0],
  158. ]);
  159. },
  160. });
  161. }
  162. }
  163. }
  164. return {
  165. ArrowFunctionExpression: spaces,
  166. };
  167. },
  168. };