dot-location.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /**
  2. * @fileoverview Validates newlines before and after dots
  3. * @author Greg Cochard
  4. */
  5. "use strict";
  6. const astUtils = require("./utils/ast-utils");
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. module.exports = {
  11. meta: {
  12. type: "layout",
  13. docs: {
  14. description: "enforce consistent newlines before and after dots",
  15. category: "Best Practices",
  16. recommended: false,
  17. url: "https://eslint.org/docs/rules/dot-location"
  18. },
  19. schema: [
  20. {
  21. enum: ["object", "property"]
  22. }
  23. ],
  24. fixable: "code",
  25. messages: {
  26. expectedDotAfterObject: "Expected dot to be on same line as object.",
  27. expectedDotBeforeProperty: "Expected dot to be on same line as property."
  28. }
  29. },
  30. create(context) {
  31. const config = context.options[0];
  32. // default to onObject if no preference is passed
  33. const onObject = config === "object" || !config;
  34. const sourceCode = context.getSourceCode();
  35. /**
  36. * Reports if the dot between object and property is on the correct loccation.
  37. * @param {ASTNode} node The `MemberExpression` node.
  38. * @returns {void}
  39. */
  40. function checkDotLocation(node) {
  41. const property = node.property;
  42. const dotToken = sourceCode.getTokenBefore(property);
  43. if (onObject) {
  44. // `obj` expression can be parenthesized, but those paren tokens are not a part of the `obj` node.
  45. const tokenBeforeDot = sourceCode.getTokenBefore(dotToken);
  46. if (!astUtils.isTokenOnSameLine(tokenBeforeDot, dotToken)) {
  47. context.report({
  48. node,
  49. loc: dotToken.loc,
  50. messageId: "expectedDotAfterObject",
  51. *fix(fixer) {
  52. if (dotToken.value.startsWith(".") && astUtils.isDecimalIntegerNumericToken(tokenBeforeDot)) {
  53. yield fixer.insertTextAfter(tokenBeforeDot, ` ${dotToken.value}`);
  54. } else {
  55. yield fixer.insertTextAfter(tokenBeforeDot, dotToken.value);
  56. }
  57. yield fixer.remove(dotToken);
  58. }
  59. });
  60. }
  61. } else if (!astUtils.isTokenOnSameLine(dotToken, property)) {
  62. context.report({
  63. node,
  64. loc: dotToken.loc,
  65. messageId: "expectedDotBeforeProperty",
  66. *fix(fixer) {
  67. yield fixer.remove(dotToken);
  68. yield fixer.insertTextBefore(property, dotToken.value);
  69. }
  70. });
  71. }
  72. }
  73. /**
  74. * Checks the spacing of the dot within a member expression.
  75. * @param {ASTNode} node The node to check.
  76. * @returns {void}
  77. */
  78. function checkNode(node) {
  79. if (!node.computed) {
  80. checkDotLocation(node);
  81. }
  82. }
  83. return {
  84. MemberExpression: checkNode
  85. };
  86. }
  87. };