1/** 2 * @fileoverview Rule to disallow whitespace before properties 3 * @author Kai Cataldo 4 */ 5"use strict"; 6 7//------------------------------------------------------------------------------ 8// Requirements 9//------------------------------------------------------------------------------ 10 11const astUtils = require("./utils/ast-utils"); 12 13//------------------------------------------------------------------------------ 14// Rule Definition 15//------------------------------------------------------------------------------ 16 17module.exports = { 18 meta: { 19 type: "layout", 20 21 docs: { 22 description: "disallow whitespace before properties", 23 category: "Stylistic Issues", 24 recommended: false, 25 url: "https://eslint.org/docs/rules/no-whitespace-before-property" 26 }, 27 28 fixable: "whitespace", 29 schema: [], 30 31 messages: { 32 unexpectedWhitespace: "Unexpected whitespace before property {{propName}}." 33 } 34 }, 35 36 create(context) { 37 const sourceCode = context.getSourceCode(); 38 39 //-------------------------------------------------------------------------- 40 // Helpers 41 //-------------------------------------------------------------------------- 42 43 /** 44 * Reports whitespace before property token 45 * @param {ASTNode} node the node to report in the event of an error 46 * @param {Token} leftToken the left token 47 * @param {Token} rightToken the right token 48 * @returns {void} 49 * @private 50 */ 51 function reportError(node, leftToken, rightToken) { 52 context.report({ 53 node, 54 messageId: "unexpectedWhitespace", 55 data: { 56 propName: sourceCode.getText(node.property) 57 }, 58 fix(fixer) { 59 let replacementText = ""; 60 61 if (!node.computed && !node.optional && astUtils.isDecimalInteger(node.object)) { 62 63 /* 64 * If the object is a number literal, fixing it to something like 5.toString() would cause a SyntaxError. 65 * Don't fix this case. 66 */ 67 return null; 68 } 69 70 // Don't fix if comments exist. 71 if (sourceCode.commentsExistBetween(leftToken, rightToken)) { 72 return null; 73 } 74 75 if (node.optional) { 76 replacementText = "?."; 77 } else if (!node.computed) { 78 replacementText = "."; 79 } 80 81 return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], replacementText); 82 } 83 }); 84 } 85 86 //-------------------------------------------------------------------------- 87 // Public 88 //-------------------------------------------------------------------------- 89 90 return { 91 MemberExpression(node) { 92 let rightToken; 93 let leftToken; 94 95 if (!astUtils.isTokenOnSameLine(node.object, node.property)) { 96 return; 97 } 98 99 if (node.computed) { 100 rightToken = sourceCode.getTokenBefore(node.property, astUtils.isOpeningBracketToken); 101 leftToken = sourceCode.getTokenBefore(rightToken, node.optional ? 1 : 0); 102 } else { 103 rightToken = sourceCode.getFirstToken(node.property); 104 leftToken = sourceCode.getTokenBefore(rightToken, 1); 105 } 106 107 if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) { 108 reportError(node, leftToken, rightToken); 109 } 110 } 111 }; 112 } 113}; 114