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