]> git.proxmox.com Git - pve-eslint.git/blame - eslint/lib/rules/no-useless-computed-key.js
bump version to 8.41.0-3
[pve-eslint.git] / eslint / lib / rules / no-useless-computed-key.js
CommitLineData
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
11const astUtils = require("./utils/ast-utils");
12
609c276f
TL
13//------------------------------------------------------------------------------
14// Helpers
15//------------------------------------------------------------------------------
16
17/**
18 * Determines whether the computed key syntax is unnecessarily used for the given node.
19 * In particular, it determines whether removing the square brackets and using the content between them
20 * directly as the key (e.g. ['foo'] -> 'foo') would produce valid syntax and preserve the same behavior.
21 * Valid non-computed keys are only: identifiers, number literals and string literals.
22 * Only literals can preserve the same behavior, with a few exceptions for specific node types:
23 * Property
24 * - { ["__proto__"]: foo } defines a property named "__proto__"
25 * { "__proto__": foo } defines object's prototype
26 * PropertyDefinition
27 * - class C { ["constructor"]; } defines an instance field named "constructor"
28 * class C { "constructor"; } produces a parsing error
29 * - class C { static ["constructor"]; } defines a static field named "constructor"
30 * class C { static "constructor"; } produces a parsing error
31 * - class C { static ["prototype"]; } produces a runtime error (doesn't break the whole script)
32 * class C { static "prototype"; } produces a parsing error (breaks the whole script)
33 * MethodDefinition
34 * - class C { ["constructor"]() {} } defines a prototype method named "constructor"
35 * class C { "constructor"() {} } defines the constructor
36 * - class C { static ["prototype"]() {} } produces a runtime error (doesn't break the whole script)
37 * class C { static "prototype"() {} } produces a parsing error (breaks the whole script)
38 * @param {ASTNode} node The node to check. It can be `Property`, `PropertyDefinition` or `MethodDefinition`.
39 * @throws {Error} (Unreachable.)
40 * @returns {void} `true` if the node has useless computed key.
41 */
42function hasUselessComputedKey(node) {
43 if (!node.computed) {
44 return false;
45 }
46
47 const { key } = node;
48
49 if (key.type !== "Literal") {
50 return false;
51 }
52
53 const { value } = key;
54
55 if (typeof value !== "number" && typeof value !== "string") {
56 return false;
57 }
58
59 switch (node.type) {
60 case "Property":
61 return value !== "__proto__";
62
63 case "PropertyDefinition":
64 if (node.static) {
65 return value !== "constructor" && value !== "prototype";
66 }
67
68 return value !== "constructor";
69
70 case "MethodDefinition":
71 if (node.static) {
72 return value !== "prototype";
73 }
74
75 return value !== "constructor";
76
8f9d1d4d 77 /* c8 ignore next */
609c276f
TL
78 default:
79 throw new Error(`Unexpected node type: ${node.type}`);
80 }
81
82}
83
eb39fafa
DC
84//------------------------------------------------------------------------------
85// Rule Definition
86//------------------------------------------------------------------------------
87
34eeec05 88/** @type {import('../shared/types').Rule} */
eb39fafa
DC
89module.exports = {
90 meta: {
91 type: "suggestion",
92
93 docs: {
8f9d1d4d 94 description: "Disallow unnecessary computed property keys in objects and classes",
eb39fafa 95 recommended: false,
f2a92ac6 96 url: "https://eslint.org/docs/latest/rules/no-useless-computed-key"
eb39fafa
DC
97 },
98
99 schema: [{
100 type: "object",
101 properties: {
102 enforceForClassMembers: {
103 type: "boolean",
104 default: false
105 }
106 },
107 additionalProperties: false
108 }],
109 fixable: "code",
110
111 messages: {
112 unnecessarilyComputedProperty: "Unnecessarily computed property [{{property}}] found."
113 }
114 },
115 create(context) {
f2a92ac6 116 const sourceCode = context.sourceCode;
eb39fafa
DC
117 const enforceForClassMembers = context.options[0] && context.options[0].enforceForClassMembers;
118
119 /**
120 * Reports a given node if it violated this rule.
121 * @param {ASTNode} node The node to check.
122 * @returns {void}
123 */
124 function check(node) {
609c276f
TL
125 if (hasUselessComputedKey(node)) {
126 const { key } = node;
eb39fafa 127
eb39fafa
DC
128 context.report({
129 node,
130 messageId: "unnecessarilyComputedProperty",
131 data: { property: sourceCode.getText(key) },
132 fix(fixer) {
133 const leftSquareBracket = sourceCode.getTokenBefore(key, astUtils.isOpeningBracketToken);
134 const rightSquareBracket = sourceCode.getTokenAfter(key, astUtils.isClosingBracketToken);
135
136 // If there are comments between the brackets and the property name, don't do a fix.
137 if (sourceCode.commentsExistBetween(leftSquareBracket, rightSquareBracket)) {
138 return null;
139 }
140
141 const tokenBeforeLeftBracket = sourceCode.getTokenBefore(leftSquareBracket);
142
143 // Insert a space before the key to avoid changing identifiers, e.g. ({ get[2]() {} }) to ({ get2() {} })
144 const needsSpaceBeforeKey = tokenBeforeLeftBracket.range[1] === leftSquareBracket.range[0] &&
145 !astUtils.canTokensBeAdjacent(tokenBeforeLeftBracket, sourceCode.getFirstToken(key));
146
147 const replacementKey = (needsSpaceBeforeKey ? " " : "") + key.raw;
148
149 return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], replacementKey);
150 }
151 });
152 }
153 }
154
5422a9cc
TL
155 /**
156 * A no-op function to act as placeholder for checking a node when the `enforceForClassMembers` option is `false`.
157 * @returns {void}
158 * @private
159 */
160 function noop() {}
161
eb39fafa
DC
162 return {
163 Property: check,
609c276f
TL
164 MethodDefinition: enforceForClassMembers ? check : noop,
165 PropertyDefinition: enforceForClassMembers ? check : noop
eb39fafa
DC
166 };
167 }
168};