1/** 2 * @fileoverview Rule to disallow unnecessary computed property keys in object literals 3 * @author Burak Yigit Kaya 4 */ 5"use strict"; 6 7//------------------------------------------------------------------------------ 8// Requirements 9//------------------------------------------------------------------------------ 10 11const lodash = require("lodash"); 12const astUtils = require("./utils/ast-utils"); 13 14//------------------------------------------------------------------------------ 15// Rule Definition 16//------------------------------------------------------------------------------ 17 18module.exports = { 19 meta: { 20 type: "suggestion", 21 22 docs: { 23 description: "disallow unnecessary computed property keys in objects and classes", 24 category: "ECMAScript 6", 25 recommended: false, 26 url: "https://eslint.org/docs/rules/no-useless-computed-key" 27 }, 28 29 schema: [{ 30 type: "object", 31 properties: { 32 enforceForClassMembers: { 33 type: "boolean", 34 default: false 35 } 36 }, 37 additionalProperties: false 38 }], 39 fixable: "code", 40 41 messages: { 42 unnecessarilyComputedProperty: "Unnecessarily computed property [{{property}}] found." 43 } 44 }, 45 create(context) { 46 const sourceCode = context.getSourceCode(); 47 const enforceForClassMembers = context.options[0] && context.options[0].enforceForClassMembers; 48 49 /** 50 * Reports a given node if it violated this rule. 51 * @param {ASTNode} node The node to check. 52 * @returns {void} 53 */ 54 function check(node) { 55 if (!node.computed) { 56 return; 57 } 58 59 const key = node.key, 60 nodeType = typeof key.value; 61 62 let allowedKey; 63 64 if (node.type === "MethodDefinition") { 65 allowedKey = node.static ? "prototype" : "constructor"; 66 } else { 67 allowedKey = "__proto__"; 68 } 69 70 if (key.type === "Literal" && (nodeType === "string" || nodeType === "number") && key.value !== allowedKey) { 71 context.report({ 72 node, 73 messageId: "unnecessarilyComputedProperty", 74 data: { property: sourceCode.getText(key) }, 75 fix(fixer) { 76 const leftSquareBracket = sourceCode.getTokenBefore(key, astUtils.isOpeningBracketToken); 77 const rightSquareBracket = sourceCode.getTokenAfter(key, astUtils.isClosingBracketToken); 78 79 // If there are comments between the brackets and the property name, don't do a fix. 80 if (sourceCode.commentsExistBetween(leftSquareBracket, rightSquareBracket)) { 81 return null; 82 } 83 84 const tokenBeforeLeftBracket = sourceCode.getTokenBefore(leftSquareBracket); 85 86 // Insert a space before the key to avoid changing identifiers, e.g. ({ get[2]() {} }) to ({ get2() {} }) 87 const needsSpaceBeforeKey = tokenBeforeLeftBracket.range[1] === leftSquareBracket.range[0] && 88 !astUtils.canTokensBeAdjacent(tokenBeforeLeftBracket, sourceCode.getFirstToken(key)); 89 90 const replacementKey = (needsSpaceBeforeKey ? " " : "") + key.raw; 91 92 return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], replacementKey); 93 } 94 }); 95 } 96 } 97 98 return { 99 Property: check, 100 MethodDefinition: enforceForClassMembers ? check : lodash.noop 101 }; 102 } 103}; 104