switch-colon-spacing.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /**
  2. * @fileoverview Rule to enforce spacing around colons of switch statements.
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Rule Definition
  12. //------------------------------------------------------------------------------
  13. module.exports = {
  14. meta: {
  15. type: "layout",
  16. docs: {
  17. description: "enforce spacing around colons of switch statements",
  18. category: "Stylistic Issues",
  19. recommended: false,
  20. url: "https://eslint.org/docs/rules/switch-colon-spacing"
  21. },
  22. schema: [
  23. {
  24. type: "object",
  25. properties: {
  26. before: { type: "boolean", default: false },
  27. after: { type: "boolean", default: true }
  28. },
  29. additionalProperties: false
  30. }
  31. ],
  32. fixable: "whitespace",
  33. messages: {
  34. expectedBefore: "Expected space(s) before this colon.",
  35. expectedAfter: "Expected space(s) after this colon.",
  36. unexpectedBefore: "Unexpected space(s) before this colon.",
  37. unexpectedAfter: "Unexpected space(s) after this colon."
  38. }
  39. },
  40. create(context) {
  41. const sourceCode = context.getSourceCode();
  42. const options = context.options[0] || {};
  43. const beforeSpacing = options.before === true; // false by default
  44. const afterSpacing = options.after !== false; // true by default
  45. /**
  46. * Get the colon token of the given SwitchCase node.
  47. * @param {ASTNode} node The SwitchCase node to get.
  48. * @returns {Token} The colon token of the node.
  49. */
  50. function getColonToken(node) {
  51. if (node.test) {
  52. return sourceCode.getTokenAfter(node.test, astUtils.isColonToken);
  53. }
  54. return sourceCode.getFirstToken(node, 1);
  55. }
  56. /**
  57. * Check whether the spacing between the given 2 tokens is valid or not.
  58. * @param {Token} left The left token to check.
  59. * @param {Token} right The right token to check.
  60. * @param {boolean} expected The expected spacing to check. `true` if there should be a space.
  61. * @returns {boolean} `true` if the spacing between the tokens is valid.
  62. */
  63. function isValidSpacing(left, right, expected) {
  64. return (
  65. astUtils.isClosingBraceToken(right) ||
  66. !astUtils.isTokenOnSameLine(left, right) ||
  67. sourceCode.isSpaceBetweenTokens(left, right) === expected
  68. );
  69. }
  70. /**
  71. * Check whether comments exist between the given 2 tokens.
  72. * @param {Token} left The left token to check.
  73. * @param {Token} right The right token to check.
  74. * @returns {boolean} `true` if comments exist between the given 2 tokens.
  75. */
  76. function commentsExistBetween(left, right) {
  77. return sourceCode.getFirstTokenBetween(
  78. left,
  79. right,
  80. {
  81. includeComments: true,
  82. filter: astUtils.isCommentToken
  83. }
  84. ) !== null;
  85. }
  86. /**
  87. * Fix the spacing between the given 2 tokens.
  88. * @param {RuleFixer} fixer The fixer to fix.
  89. * @param {Token} left The left token of fix range.
  90. * @param {Token} right The right token of fix range.
  91. * @param {boolean} spacing The spacing style. `true` if there should be a space.
  92. * @returns {Fix|null} The fix object.
  93. */
  94. function fix(fixer, left, right, spacing) {
  95. if (commentsExistBetween(left, right)) {
  96. return null;
  97. }
  98. if (spacing) {
  99. return fixer.insertTextAfter(left, " ");
  100. }
  101. return fixer.removeRange([left.range[1], right.range[0]]);
  102. }
  103. return {
  104. SwitchCase(node) {
  105. const colonToken = getColonToken(node);
  106. const beforeToken = sourceCode.getTokenBefore(colonToken);
  107. const afterToken = sourceCode.getTokenAfter(colonToken);
  108. if (!isValidSpacing(beforeToken, colonToken, beforeSpacing)) {
  109. context.report({
  110. node,
  111. loc: colonToken.loc,
  112. messageId: beforeSpacing ? "expectedBefore" : "unexpectedBefore",
  113. fix: fixer => fix(fixer, beforeToken, colonToken, beforeSpacing)
  114. });
  115. }
  116. if (!isValidSpacing(colonToken, afterToken, afterSpacing)) {
  117. context.report({
  118. node,
  119. loc: colonToken.loc,
  120. messageId: afterSpacing ? "expectedAfter" : "unexpectedAfter",
  121. fix: fixer => fix(fixer, colonToken, afterToken, afterSpacing)
  122. });
  123. }
  124. }
  125. };
  126. }
  127. };