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