no-whitespace-before-property.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * @fileoverview Rule to disallow whitespace before properties
  3. * @author Kai Cataldo
  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: "Disallow whitespace before properties",
  19. recommended: false,
  20. url: "https://eslint.org/docs/rules/no-whitespace-before-property"
  21. },
  22. fixable: "whitespace",
  23. schema: [],
  24. messages: {
  25. unexpectedWhitespace: "Unexpected whitespace before property {{propName}}."
  26. }
  27. },
  28. create(context) {
  29. const sourceCode = context.getSourceCode();
  30. //--------------------------------------------------------------------------
  31. // Helpers
  32. //--------------------------------------------------------------------------
  33. /**
  34. * Reports whitespace before property token
  35. * @param {ASTNode} node the node to report in the event of an error
  36. * @param {Token} leftToken the left token
  37. * @param {Token} rightToken the right token
  38. * @returns {void}
  39. * @private
  40. */
  41. function reportError(node, leftToken, rightToken) {
  42. context.report({
  43. node,
  44. messageId: "unexpectedWhitespace",
  45. data: {
  46. propName: sourceCode.getText(node.property)
  47. },
  48. fix(fixer) {
  49. let replacementText = "";
  50. if (!node.computed && !node.optional && astUtils.isDecimalInteger(node.object)) {
  51. /*
  52. * If the object is a number literal, fixing it to something like 5.toString() would cause a SyntaxError.
  53. * Don't fix this case.
  54. */
  55. return null;
  56. }
  57. // Don't fix if comments exist.
  58. if (sourceCode.commentsExistBetween(leftToken, rightToken)) {
  59. return null;
  60. }
  61. if (node.optional) {
  62. replacementText = "?.";
  63. } else if (!node.computed) {
  64. replacementText = ".";
  65. }
  66. return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], replacementText);
  67. }
  68. });
  69. }
  70. //--------------------------------------------------------------------------
  71. // Public
  72. //--------------------------------------------------------------------------
  73. return {
  74. MemberExpression(node) {
  75. let rightToken;
  76. let leftToken;
  77. if (!astUtils.isTokenOnSameLine(node.object, node.property)) {
  78. return;
  79. }
  80. if (node.computed) {
  81. rightToken = sourceCode.getTokenBefore(node.property, astUtils.isOpeningBracketToken);
  82. leftToken = sourceCode.getTokenBefore(rightToken, node.optional ? 1 : 0);
  83. } else {
  84. rightToken = sourceCode.getFirstToken(node.property);
  85. leftToken = sourceCode.getTokenBefore(rightToken, 1);
  86. }
  87. if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
  88. reportError(node, leftToken, rightToken);
  89. }
  90. }
  91. };
  92. }
  93. };