arrow-spacing.js 5.1 KB

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